Merge latest master changes

This commit is contained in:
Rodolfo Bogado
2015-07-05 22:20:03 -03:00
parent c1ab5df11f
commit 6a67e64de4
68 changed files with 1257 additions and 372 deletions

View File

@@ -13,6 +13,18 @@ option(ENABLE_QT "Enable Qt (use the experimental Qt interface)" OFF)
option(ENABLE_PCH "Use PCH to speed up compilation" ON)
option(ENABLE_LTO "Enables Link Time Optimization" OFF)
option(ENABLE_GENERIC "Enables generic build that should run on any little-endian host" OFF)
# Enable SDL for default on operating systems that aren't OSX, Android, Linux or Windows.
if(NOT APPLE AND NOT ANDROID AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT MSVC)
option(ENABLE_SDL "Enables SDL as a generic controller backend" ON)
else()
option(ENABLE_SDL "Enables SDL as a generic controller backend" OFF)
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT ANDROID)
option(ENABLE_EVDEV "Enables the evdev controller backend" ON)
endif()
if(APPLE)
option(OSX_USE_DEFAULT_SEARCH_PATH "Don't prioritize system library paths" OFF)
endif()
@@ -300,6 +312,14 @@ if(WIN32)
add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
endif(WIN32)
# Dolphin requires threads.
# The Apple build may not need an explicit flag because one of the
# frameworks may already provide it.
# But for non-OSX systems, we will use the CMake Threads package.
IF(NOT APPLE)
FIND_PACKAGE(Threads)
ENDIF(NOT APPLE)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING
"Build type (Release/Debug/RelWithDebInfo/MinSizeRe)" FORCE)
@@ -469,7 +489,7 @@ if(NOT ANDROID)
if(ENCODE_FRAMEDUMPS)
check_libav()
if(LIBAV_FOUND)
LIST(APPEND LIBS ${LIBAV_LIBRARIES})
LIST(APPEND LIBS ${LIBAV_LDFLAGS})
endif()
endif()
@@ -508,6 +528,19 @@ if(USE_EGL)
add_definitions(-DUSE_EGL=1)
endif()
if(ENABLE_EVDEV)
include(FindLibudev REQUIRED)
include(FindLibevdev REQUIRED)
if(LIBUDEV_FOUND AND LIBEVDEV_FOUND)
message("libevdev/libudev found, enabling evdev controller backend")
add_definitions(-DHAVE_LIBUDEV=1)
add_definitions(-DHAVE_LIBEVDEV=1)
include_directories(${LIBUDEV_INCLUDE_DIR} ${LIBEVDEV_INCLUDE_DIR})
else()
message(FATAL_ERROR "Couldn't find libevdev and/or libudev. Can't build evdev controller backend.\nDisable ENABLE_EVDEV if you wish to build without controller support")
endif()
endif()
########################################
# Setup include directories (and make sure they are preferred over the Externals)
#
@@ -614,26 +647,21 @@ if(OPENAL_FOUND)
endif()
endif()
if(NOT ANDROID)
if(NOT APPLE)
include(FindSDL2 OPTIONAL)
endif()
if(ENABLE_SDL)
include(FindSDL2 OPTIONAL)
if(SDL2_FOUND)
message("Using shared SDL2")
add_definitions(-DHAVE_SDL=1)
include_directories(${SDL2_INCLUDE_DIR})
else(SDL2_FOUND)
# SDL2 not found, try SDL
if(NOT APPLE)
include(FindSDL OPTIONAL)
endif()
include(FindSDL OPTIONAL)
if(SDL_FOUND)
message("Using shared SDL")
add_definitions(-DHAVE_SDL=1)
include_directories(${SDL_INCLUDE_DIR})
else(SDL_FOUND)
message("SDL NOT found, disabling SDL input")
add_definitions(-DHAVE_SDL=0)
endif(SDL_FOUND)
endif(SDL2_FOUND)
endif()
@@ -781,7 +809,7 @@ if(NOT DISABLE_WX AND NOT ANDROID)
message(FATAL_ERROR "wxWidgets in Externals is not compatible with your platform")
endif()
include_directories(
include_directories(SYSTEM
Externals/wxWidgets3
Externals/wxWidgets3/include)
add_subdirectory(Externals/wxWidgets3)

View File

@@ -0,0 +1,33 @@
# - Try to find libevdev
# Once done this will define
# LIBEVDEV_FOUND - System has libevdev
# LIBEVDEV_INCLUDE_DIRS - The libevdev include directories
# LIBEVDEV_LIBRARIES - The libraries needed to use libevdev
find_package(PkgConfig)
pkg_check_modules(PC_LIBEVDEV QUIET libevdev)
FIND_PATH(
LIBEVDEV_INCLUDE_DIR libevdev/libevdev.h
HINTS ${PC_LIBEVDEV_INCLUDEDIR} ${PC_LIBEVDEV_INCLUDE_DIRS}
/usr/include
/usr/local/include
${LIBEVDEV_PATH_INCLUDES}
)
FIND_LIBRARY(
LIBEVDEV_LIBRARY
NAMES evdev libevdev
HINTS ${PC_LIBEVDEV_LIBDIR} ${PC_LIBEVDEV_LIBRARY_DIRS}
PATHS ${ADDITIONAL_LIBRARY_PATHS}
${LIBEVDEV_PATH_LIB}
)
set(LIBEVDEV_LIBRARIES ${LIBEVDEV_LIBRARY} )
set(LIBEVDEV_INCLUDE_DIRS ${LIBEVDEV_INCLUDE_DIR} )
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(libevdev DEFAULT_MSG
LIBEVDEV_LIBRARY LIBEVDEV_INCLUDE_DIR)
mark_as_advanced(LIBEVDEV_INCLUDE_DIR LIBEVDEV_LIBRARY )

View File

@@ -0,0 +1,28 @@
# - Try to find LIBUDEV
# Once done this will define
# LIBUDEV_FOUND - System has LIBUDEV
# LIBUDEV_INCLUDE_DIRS - The LIBUDEV include directories
# LIBUDEV_LIBRARIES - The libraries needed to use LIBUDEV
FIND_PATH(
LIBUDEV_INCLUDE_DIR libudev.h
/usr/include
/usr/local/include
${LIBUDEV_PATH_INCLUDES}
)
FIND_LIBRARY(
LIBUDEV_LIBRARY
NAMES udev libudev
PATHS ${ADDITIONAL_LIBRARY_PATHS}
${LIBUDEV_PATH_LIB}
)
set(LIBUDEV_LIBRARIES ${LIBUDEV_LIBRARY} )
set(LIBUDEV_INCLUDE_DIRS ${LIBUDEV_INCLUDE_DIR} )
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LIBUDEV DEFAULT_MSG
LIBUDEV_LIBRARY LIBUDEV_INCLUDE_DIR)
mark_as_advanced(LIBUDEV_INCLUDE_DIR LIBUDEV_LIBRARY )

View File

@@ -34,6 +34,7 @@ if (POLARSSL_FOUND)
set(CMAKE_REQUIRED_LIBRARIES ${POLARSSL_LIBRARY})
unset(POLARSSL_WORKS CACHE)
check_cxx_source_compiles("
#include <cstring>
#include <polarssl/ctr_drbg.h>
#include <polarssl/entropy.h>
#include <polarssl/net.h>

View File

@@ -172,9 +172,22 @@ IF(SDL2_LIBRARY_TEMP)
SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "")
SET(SDL2_FOUND "YES")
# extract the major and minor version numbers from SDL2/SDL_version.h
# we have to handle framework a little bit differently :
if("${SDL2_INCLUDE_DIR}" MATCHES ".framework")
set(SDL2_VERSION_H_INPUT "${SDL2_INCLUDE_DIR}/Headers/SDL_version.h")
else()
set(SDL2_VERSION_H_INPUT "${SDL2_INCLUDE_DIR}/SDL_version.h")
endif()
FILE(READ "${SDL2_VERSION_H_INPUT}" SDL2_VERSION_H_CONTENTS)
STRING(REGEX REPLACE ".*#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+).*#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+).*#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+).*"
"\\1.\\2.\\3" SDL2_VERSION "${SDL2_VERSION_H_CONTENTS}")
#MESSAGE("SDL2 Version is ${SDL2_VERSION}")
ENDIF(SDL2_LIBRARY_TEMP)
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2
REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR)
REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR VERSION_VAR SDL2_VERSION)

Binary file not shown.

View File

@@ -2,6 +2,7 @@
[Core]
# Values set here will override the main Dolphin settings.
SyncGPU = True
[EmuState]
# The Emulation State. 1 is worst, 5 is best, 0 is not set.

View File

@@ -6,7 +6,7 @@
[EmuState]
# The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationStateId = 4
EmulationIssues = Everything playable with minor glitches.
EmulationIssues =
[OnLoad]
# Add memory patches to be loaded once on boot here.
@@ -18,7 +18,4 @@ EmulationIssues = Everything playable with minor glitches.
# Add action replay cheats here.
[Video_Settings]
SafeTextureCacheColorSamples = 512
[Video_Hacks]
SafeTextureCacheColorSamples = 4096

View File

@@ -2,6 +2,7 @@
[Core]
# Values set here will override the main Dolphin settings.
SyncGPU = True
[EmuState]
# The Emulation State. 1 is worst, 5 is best, 0 is not set.

View File

@@ -4,6 +4,7 @@
[Core]
# Values set here will override the main Dolphin settings.
FPRF = True
SyncGPU = True
[EmuState]
# The Emulation State. 1 is worst, 5 is best, 0 is not set.

View File

@@ -2,6 +2,7 @@
[Core]
# Values set here will override the main Dolphin settings.
SyncGPU = True
[EmuState]
# The Emulation State. 1 is worst, 5 is best, 0 is not set.
@@ -19,6 +20,4 @@ EmulationIssues = HLE music fades in and out. If EFB scale is not integral, 1x,
[Video_Settings]
EFBScale = -1
SafeTextureCacheColorSamples = 0

View File

@@ -2,11 +2,12 @@
[Core]
# Values set here will override the main Dolphin settings.
SyncGPU = True
[EmuState]
# The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationStateId = 3
EmulationIssues = Unstable with graphical glitches.
EmulationIssues = Has graphical glitches.
[OnLoad]
# Add memory patches to be loaded once on boot here.

View File

@@ -5,7 +5,6 @@
[EmuState]
# The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationIssues = Enable EFB to RAM for the coins to spin (it will cause a big slowdown).
EmulationStateId = 4
[OnLoad]
@@ -21,4 +20,3 @@ EmulationStateId = 4
SafeTextureCacheColorSamples = 512
[Video_Hacks]

View File

@@ -277,7 +277,7 @@ public final class NativeLibrary
public static void endEmulationActivity()
{
Log.v("DolphinEmu", "Ending EmulationActivity.");
mEmulationActivity.finish();
mEmulationActivity.exitWithAnimation();
}
public static void setEmulationActivity(EmulationActivity emulationActivity)

View File

@@ -12,6 +12,12 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
@@ -22,10 +28,15 @@ import java.util.List;
public final class EmulationActivity extends AppCompatActivity
{
private View mDecorView;
private ImageView mImageView;
private FrameLayout mFrameEmulation;
private boolean mDeviceHasTouchScreen;
private boolean mSystemUiVisible;
// So that MainActivity knows which view to invalidate before the return animation.
private int mPosition;
/**
* Handlers are a way to pass a message to an Activity telling it to do something
* on the UI thread. This Handler responds to any message, even blank ones, by
@@ -39,12 +50,18 @@ public final class EmulationActivity extends AppCompatActivity
hideSystemUI();
}
};
private String mScreenPath;
private FrameLayout mFrameContent;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Picasso will take a while to load these big-ass screenshots. So don't run
// the animation until we say so.
postponeEnterTransition();
mDeviceHasTouchScreen = getPackageManager().hasSystemFeature("android.hardware.touchscreen");
// Get a handle to the Window containing the UI.
@@ -79,9 +96,57 @@ public final class EmulationActivity extends AppCompatActivity
setContentView(R.layout.activity_emulation);
mImageView = (ImageView) findViewById(R.id.image_screenshot);
mFrameContent = (FrameLayout) findViewById(R.id.frame_content);
mFrameEmulation = (FrameLayout) findViewById(R.id.frame_emulation_fragment);
Intent gameToEmulate = getIntent();
String path = gameToEmulate.getStringExtra("SelectedGame");
String title = gameToEmulate.getStringExtra("SelectedTitle");
mScreenPath = gameToEmulate.getStringExtra("ScreenPath");
mPosition = gameToEmulate.getIntExtra("GridPosition", -1);
Picasso.with(this)
.load(mScreenPath)
.noFade()
.noPlaceholder()
.into(mImageView, new Callback()
{
@Override
public void onSuccess()
{
scheduleStartPostponedTransition(mImageView);
}
@Override
public void onError()
{
// Still have to do this, or else the app will crash.
scheduleStartPostponedTransition(mImageView);
}
});
mImageView.animate()
.withLayer()
.setStartDelay(2000)
.setDuration(500)
.alpha(0.0f)
.withStartAction(new Runnable()
{
@Override
public void run()
{
mFrameEmulation.setVisibility(View.VISIBLE);
}
})
.withEndAction(new Runnable()
{
@Override
public void run()
{
mImageView.setVisibility(View.GONE);
}
});
setTitle(title);
@@ -90,7 +155,7 @@ public final class EmulationActivity extends AppCompatActivity
// Add fragment to the activity - this triggers all its lifecycle callbacks.
getFragmentManager().beginTransaction()
.add(R.id.frame_content, emulationFragment, EmulationFragment.FRAGMENT_TAG)
.add(R.id.frame_emulation_fragment, emulationFragment, EmulationFragment.FRAGMENT_TAG)
.commit();
}
@@ -155,6 +220,59 @@ public final class EmulationActivity extends AppCompatActivity
}
}
public void exitWithAnimation()
{
runOnUiThread(new Runnable()
{
@Override
public void run()
{
Picasso.with(EmulationActivity.this)
.invalidate(mScreenPath);
Picasso.with(EmulationActivity.this)
.load(mScreenPath)
.noFade()
.noPlaceholder()
.into(mImageView, new Callback()
{
@Override
public void onSuccess()
{
showScreenshot();
}
@Override
public void onError()
{
finish();
}
});
}
});
}
private void showScreenshot()
{
mImageView.setVisibility(View.VISIBLE);
mImageView.animate()
.withLayer()
.setDuration(500)
.alpha(1.0f)
.withEndAction(afterShowingScreenshot);
}
private Runnable afterShowingScreenshot = new Runnable()
{
@Override
public void run()
{
mFrameContent.removeView(mFrameEmulation);
setResult(mPosition);
finishAfterTransition();
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
@@ -324,4 +442,20 @@ public final class EmulationActivity extends AppCompatActivity
hideSystemUiAfterDelay();
}
private void scheduleStartPostponedTransition(final View sharedElement)
{
sharedElement.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener()
{
@Override
public boolean onPreDraw()
{
sharedElement.getViewTreeObserver().removeOnPreDrawListener(this);
startPostponedEnterTransition();
return true;
}
});
}
}

View File

@@ -36,6 +36,7 @@ import org.dolphinemu.dolphinemu.services.AssetCopyService;
public final class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>
{
private static final int REQUEST_ADD_DIRECTORY = 1;
public static final int REQUEST_EMULATE_GAME = 2;
/**
* It is important to keep track of loader ID separately from platform ID (see Game.java)
@@ -115,15 +116,29 @@ public final class MainActivity extends AppCompatActivity implements LoaderManag
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent result)
{
// If the user picked a file, as opposed to just backing out.
if (resultCode == RESULT_OK)
switch (requestCode)
{
// Sanity check to make sure the Activity that just returned was the AddDirectoryActivity;
// other activities might use this callback in the future (don't forget to change Javadoc!)
if (requestCode == REQUEST_ADD_DIRECTORY)
{
refreshFragment();
}
case REQUEST_ADD_DIRECTORY:
// If the user picked a file, as opposed to just backing out.
if (resultCode == RESULT_OK)
{
// Sanity check to make sure the Activity that just returned was the AddDirectoryActivity;
// other activities might use this callback in the future (don't forget to change Javadoc!)
if (requestCode == REQUEST_ADD_DIRECTORY)
{
refreshFragment();
}
}
break;
case REQUEST_EMULATE_GAME:
// Invalidate Picasso image so that the new screenshot is animated in.
PlatformGamesFragment fragment = getPlatformFragment(mViewPager.getCurrentItem());
if (fragment != null)
{
fragment.refreshScreenshotAtPosition(resultCode);
}
}
}

View File

@@ -1,9 +1,11 @@
package org.dolphinemu.dolphinemu.adapters;
import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Intent;
import android.database.Cursor;
import android.database.DataSetObserver;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
@@ -15,6 +17,7 @@ import com.squareup.picasso.Picasso;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.activities.MainActivity;
import org.dolphinemu.dolphinemu.dialogs.GameDetailsDialog;
import org.dolphinemu.dolphinemu.model.GameDatabase;
import org.dolphinemu.dolphinemu.viewholders.GameViewHolder;
@@ -80,14 +83,15 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
if (mCursor.moveToPosition(position))
{
String screenPath = mCursor.getString(GameDatabase.GAME_COLUMN_SCREENSHOT_PATH);
Picasso.with(holder.imageScreenshot.getContext())
.invalidate(screenPath);
// Fill in the view contents.
Picasso.with(holder.imageScreenshot.getContext())
.load(screenPath)
.fit()
.centerCrop()
.noFade()
.noPlaceholder()
.config(Bitmap.Config.RGB_565)
.error(R.drawable.no_banner)
.into(holder.imageScreenshot);
@@ -112,8 +116,6 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
{
Log.e("DolphinEmu", "Can't bind view; dataset is not valid.");
}
}
/**
@@ -220,8 +222,17 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
intent.putExtra("SelectedGame", holder.path);
intent.putExtra("SelectedTitle", holder.title);
intent.putExtra("ScreenPath", holder.screenshotPath);
intent.putExtra("GridPosition", holder.getAdapterPosition());
view.getContext().startActivity(intent);
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(
(Activity) view.getContext(),
holder.imageScreenshot,
"image_game_screenshot");
((Activity) view.getContext()).startActivityForResult(intent,
MainActivity.REQUEST_EMULATE_GAME,
options.toBundle());
}
/**

View File

@@ -1,12 +1,12 @@
package org.dolphinemu.dolphinemu.fragments;
import android.app.Activity;
import android.app.Fragment;
import android.app.LoaderManager;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
@@ -57,6 +57,15 @@ public class PlatformGamesFragment extends Fragment
RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(),
getResources().getInteger(R.integer.game_grid_columns));
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator()
{
@Override
public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY)
{
dispatchChangeFinished(newHolder, false);
return true;
}
});
recyclerView.addItemDecoration(new GameAdapter.SpacesItemDecoration(8));
@@ -70,10 +79,9 @@ public class PlatformGamesFragment extends Fragment
return rootView;
}
@Override
public void onAttach(Activity activity)
public void refreshScreenshotAtPosition(int position)
{
super.onAttach(activity);
mAdapter.notifyItemChanged(position);
}
public void refresh()

View File

@@ -1,5 +1,19 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/frame_content">
android:id="@+id/frame_content"
>
<FrameLayout
android:id="@+id/frame_emulation_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/image_screenshot"
android:transitionName="image_game_screenshot"/>
</FrameLayout>

View File

@@ -20,7 +20,7 @@
android:id="@+id/image_game_screen"
android:layout_width="match_parent"
android:layout_height="0dp"
android:transitionName="image_game_screen"
android:transitionName="image_game_screenshot"
android:layout_weight="1"
tools:src="@drawable/placeholder_screenshot"
tools:scaleType="centerCrop"/>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<transitionSet>
<changeImageTransform/>
</transitionSet>

View File

@@ -7,6 +7,13 @@
<item name="colorPrimary">@color/dolphin_blue</item>
<!-- darker variant for the status bar and contextual app bars -->
<item name="colorPrimaryDark">@color/dolphin_blue_dark</item>
<!--enable window content transitions-->
<item name="android:windowContentTransitions">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>
<item name="android:colorControlHighlight">?attr/colorAccent</item>
</style>
<!-- Same as above, but use default action bar, and mandate margins. -->
@@ -62,10 +69,17 @@
<item name="colorAccent">@color/dolphin_accent_wiiware</item>
</style>
<style name="DolphinEmulationBase" parent="Theme.AppCompat.Light.DarkActionBar">
<style name="DolphinEmulationBase" parent="Theme.AppCompat">
<item name="colorPrimary">@color/dolphin_blue</item>
<item name="colorPrimaryDark">@color/dolphin_blue_dark</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:windowBackground">@android:color/black</item>
<!--enable window content transitions-->
<item name="android:windowContentTransitions">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>
</style>
<!-- Inherit from the Base Dolphin Emulation Theme-->
@@ -81,7 +95,6 @@
<item name="colorAccent">@color/dolphin_accent_wiiware</item>
</style>
<!-- Hax to make Tablayout render icons -->
<style name="MyCustomTextAppearance" parent="TextAppearance.Design.Tab">
<item name="textAllCaps">false</item>

View File

@@ -4,5 +4,10 @@ add_subdirectory(Core)
add_subdirectory(DiscIO)
add_subdirectory(DolphinWX)
add_subdirectory(InputCommon)
add_subdirectory(UICommon)
add_subdirectory(VideoCommon)
add_subdirectory(VideoBackends)
add_subdirectory(VideoBackends)
if(ENABLE_QT)
add_subdirectory(DolphinQt)
endif()

View File

@@ -406,7 +406,7 @@ static const u32 LogicalEnc[][2] = {
};
// Load/Store Exclusive
static u32 LoadStoreExcEnc[][5] = {
static const u32 LoadStoreExcEnc[][5] = {
{0, 0, 0, 0, 0}, // STXRB
{0, 0, 0, 0, 1}, // STLXRB
{0, 0, 1, 0, 0}, // LDXRB
@@ -1523,6 +1523,21 @@ void ARM64XEmitter::UBFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms)
{
EncodeBitfieldMOVInst(2, Rd, Rn, immr, imms);
}
void ARM64XEmitter::BFI(ARM64Reg Rd, ARM64Reg Rn, u32 lsb, u32 width)
{
u32 size = Is64Bit(Rn) ? 64 : 32;
_assert_msg_(DYNA_REC, (lsb + width) <= size, "%s passed lsb %d and width %d which is greater than the register size!",
__FUNCTION__, lsb, width);
EncodeBitfieldMOVInst(1, Rd, Rn, (size - lsb) % size, width - 1);
}
void ARM64XEmitter::UBFIZ(ARM64Reg Rd, ARM64Reg Rn, u32 lsb, u32 width)
{
u32 size = Is64Bit(Rn) ? 64 : 32;
_assert_msg_(DYNA_REC, (lsb + width) <= size, "%s passed lsb %d and width %d which is greater than the register size!",
__FUNCTION__, lsb, width);
EncodeBitfieldMOVInst(2, Rd, Rn, (size - lsb) % size, width - 1);
}
void ARM64XEmitter::EXTR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u32 shift)
{
bool sf = Is64Bit(Rd);

View File

@@ -578,6 +578,8 @@ public:
void BFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms);
void SBFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms);
void UBFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms);
void BFI(ARM64Reg Rd, ARM64Reg Rn, u32 lsb, u32 width);
void UBFIZ(ARM64Reg Rd, ARM64Reg Rn, u32 lsb, u32 width);
// Extract register (ROR with two inputs, if same then faster on A67)
void EXTR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u32 shift);
@@ -591,7 +593,7 @@ public:
void UBFX(ARM64Reg Rd, ARM64Reg Rn, int lsb, int width)
{
UBFM(Rd, Rn, lsb, lsb + width <= (Is64Bit(Rn) ? 64 : 32));
UBFM(Rd, Rn, lsb, lsb + width - 1);
}
// Load Register (Literal)
@@ -709,10 +711,9 @@ public:
// (this method might be a thunk in the case of multi-inheritance) so we
// have to go through a trampoline function.
template <typename T, typename... Args>
static void CallLambdaTrampoline(const std::function<T(Args...)>* f,
Args... args)
static T CallLambdaTrampoline(const std::function<T(Args...)>* f, Args... args)
{
(*f)(args...);
return (*f)(args...);
}
// This function expects you to have set up the state.

View File

@@ -209,23 +209,23 @@ double ApproximateReciprocal(double val)
// Special case 0
if (mantissa == 0 && exponent == 0)
return sign ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity();
return std::copysign(std::numeric_limits<double>::infinity(), valf);
// Special case NaN-ish numbers
if (exponent == (0x7FFLL << 52))
{
if (mantissa == 0)
return sign ? -0.0 : 0.0;
return std::copysign(0.0, valf);
return 0.0 + valf;
}
// Special case small inputs
if (exponent < (895LL << 52))
return sign ? -std::numeric_limits<float>::max() : std::numeric_limits<float>::max();
return std::copysign(std::numeric_limits<float>::max(), valf);
// Special case large inputs
if (exponent >= (1149LL << 52))
return sign ? -0.0f : 0.0f;
return std::copysign(0.0, valf);
exponent = (0x7FDLL << 52) - exponent;

View File

@@ -53,5 +53,5 @@ Symbol* SymbolDB::GetSymbolFromName(const std::string& name)
void SymbolDB::AddCompleteSymbol(const Symbol &symbol)
{
functions.insert(std::pair<u32, Symbol>(symbol.address, symbol));
functions.emplace(symbol.address, symbol);
}

View File

@@ -971,10 +971,9 @@ public:
// (this method might be a thunk in the case of multi-inheritance) so we
// have to go through a trampoline function.
template <typename T, typename... Args>
static void CallLambdaTrampoline(const std::function<T(Args...)>* f,
Args... args)
static T CallLambdaTrampoline(const std::function<T(Args...)>* f, Args... args)
{
(*f)(args...);
return (*f)(args...);
}
template <typename T, typename... Args>

View File

@@ -628,6 +628,7 @@ void SConfig::LoadDefaults()
bJITIntegerOff = false;
bJITPairedOff = false;
bJITSystemRegistersOff = false;
bJITBranchOff = false;
m_strName = "NONE";
m_strUniqueID = "00000000";

View File

@@ -42,7 +42,10 @@ static bool VerifyRoms()
// delroth's improvement on LM1234 replacement ROM (Zelda and AX only,
// IPL/Card/GBA still broken)
{ 0xd9907f71, 0xb019c2fb }
{ 0xd9907f71, 0xb019c2fb },
// above with improved resampling coefficients
{ 0xd9907f71, 0xdb6880c1 }
};
u32 hash_irom = HashAdler32((u8*)g_dsp.irom, DSP_IROM_BYTE_SIZE);
@@ -69,7 +72,7 @@ static bool VerifyRoms()
DSPHost::OSD_AddMessage("You are using an old free DSP ROM made by the Dolphin Team.", 6000);
DSPHost::OSD_AddMessage("Only games using the Zelda UCode will work correctly.", 6000);
}
else if (rom_idx == 2)
else if (rom_idx == 2 || rom_idx == 3)
{
DSPHost::OSD_AddMessage("You are using a free DSP ROM made by the Dolphin Team.", 8000);
DSPHost::OSD_AddMessage("All Wii games will work correctly, and most GC games should ", 8000);

View File

@@ -235,6 +235,7 @@ static bool CheckDeviceAccess(libusb_device* device)
if (ret == LIBUSB_ERROR_NOT_SUPPORTED)
s_libusb_driver_not_supported = true;
}
return false;
}
else if ((ret = libusb_kernel_driver_active(s_handle, 0)) == 1)
{

View File

@@ -45,6 +45,31 @@ private:
IOPMAssertionID m_pm_assertion;
};
class WiimoteDarwinHid final : public Wiimote
{
public:
WiimoteDarwinHid(IOHIDDeviceRef device);
~WiimoteDarwinHid() override;
protected:
bool ConnectInternal() override;
void DisconnectInternal() override;
bool IsConnected() const override;
void IOWakeup() override;
int IORead(u8* buf) override;
int IOWrite(u8 const* buf, size_t len) override;
private:
static void ReportCallback(void* context, IOReturn result, void* sender, IOHIDReportType type, u32 reportID, u8* report, CFIndex reportLength);
static void RemoveCallback(void* context, IOReturn result, void* sender);
void QueueBufferReport(int length);
IOHIDDeviceRef m_device;
bool m_connected;
std::atomic<bool> m_interrupted;
Report m_report_buffer;
Common::FifoQueue<Report> m_buffered_reports;
};
WiimoteScanner::WiimoteScanner()
: m_run_thread()
, m_want_wiimotes()
@@ -61,65 +86,109 @@ void WiimoteScanner::FindWiimotes(std::vector<Wiimote*> & found_wiimotes, Wiimot
// TODO: find the device in the constructor and save it for later
IOBluetoothHostController *bth;
IOBluetoothDeviceInquiry *bti;
IOHIDManagerRef hid;
SearchBT *sbt;
NSEnumerator *en;
found_board = nullptr;
bool btFailed = false;
bool hidFailed = false;
bth = [[IOBluetoothHostController alloc] init];
if ([bth addressAsString] == nil)
{
btFailed = [bth addressAsString] == nil;
if (btFailed)
WARN_LOG(WIIMOTE, "No Bluetooth host controller");
hid = IOHIDManagerCreate(NULL, kIOHIDOptionsTypeNone);
hidFailed = CFGetTypeID(hid) != IOHIDManagerGetTypeID();
if (hidFailed)
WARN_LOG(WIIMOTE, "No HID manager");
if (hidFailed && btFailed)
{
CFRelease(hid);
[bth release];
return;
}
sbt = [[SearchBT alloc] init];
sbt->maxDevices = 32;
bti = [[IOBluetoothDeviceInquiry alloc] init];
[bti setDelegate: sbt];
[bti setInquiryLength: 2];
if ([bti start] != kIOReturnSuccess)
if (!btFailed)
{
ERROR_LOG(WIIMOTE, "Unable to do Bluetooth discovery");
sbt = [[SearchBT alloc] init];
sbt->maxDevices = 32;
bti = [[IOBluetoothDeviceInquiry alloc] init];
[bti setDelegate: sbt];
[bti setInquiryLength: 2];
if ([bti start] != kIOReturnSuccess)
{
ERROR_LOG(WIIMOTE, "Unable to do Bluetooth discovery");
[bth release];
[sbt release];
btFailed = true;
}
do
{
CFRunLoopRun();
}
while (!sbt->done);
int found_devices = [[bti foundDevices] count];
if (found_devices)
NOTICE_LOG(WIIMOTE, "Found %i Bluetooth devices", found_devices);
en = [[bti foundDevices] objectEnumerator];
for (int i = 0; i < found_devices; i++)
{
IOBluetoothDevice *dev = [en nextObject];
if (!IsValidBluetoothName([[dev name] UTF8String]))
continue;
Wiimote* wm = new WiimoteDarwin([dev retain]);
if (IsBalanceBoardName([[dev name] UTF8String]))
{
found_board = wm;
}
else
{
found_wiimotes.push_back(wm);
}
}
[bth release];
[bti release];
[sbt release];
return;
}
do
if (!hidFailed)
{
NSArray *criteria = @[
@{ @kIOHIDVendorIDKey: @0x057e, @kIOHIDProductIDKey: @0x0306 },
@{ @kIOHIDVendorIDKey: @0x057e, @kIOHIDProductIDKey: @0x0330 },
];
IOHIDManagerSetDeviceMatchingMultiple(hid, (CFArrayRef)criteria);
CFRunLoopRun();
}
while (!sbt->done);
int found_devices = [[bti foundDevices] count];
if (found_devices)
NOTICE_LOG(WIIMOTE, "Found %i Bluetooth devices", found_devices);
en = [[bti foundDevices] objectEnumerator];
for (int i = 0; i < found_devices; i++)
{
IOBluetoothDevice *dev = [en nextObject];
if (!IsValidBluetoothName([[dev name] UTF8String]))
continue;
Wiimote* wm = new WiimoteDarwin([dev retain]);
if (IsBalanceBoardName([[dev name] UTF8String]))
CFSetRef devices = IOHIDManagerCopyDevices(hid);
if (devices)
{
found_board = wm;
}
else
{
found_wiimotes.push_back(wm);
}
}
int found_devices = CFSetGetCount(devices);
if (found_devices)
{
NOTICE_LOG(WIIMOTE, "Found %i HID devices", found_devices);
[bth release];
[bti release];
[sbt release];
IOHIDDeviceRef values[found_devices];
CFSetGetValues(devices, reinterpret_cast<const void**>(&values));
for (int i = 0; i < found_devices; i++)
{
Wiimote* wm = new WiimoteDarwinHid(values[i]);
found_wiimotes.push_back(wm);
}
}
}
CFRelease(hid);
}
}
bool WiimoteScanner::IsReady() const
@@ -287,6 +356,118 @@ void WiimoteDarwin::DisablePowerAssertionInternal()
}
}
WiimoteDarwinHid::WiimoteDarwinHid(IOHIDDeviceRef device) : m_device(device)
{
CFRetain(m_device);
m_connected = false;
m_report_buffer = Report(MAX_PAYLOAD);
}
WiimoteDarwinHid::~WiimoteDarwinHid()
{
Shutdown();
CFRelease(m_device);
}
bool WiimoteDarwinHid::ConnectInternal()
{
IOReturn ret = IOHIDDeviceOpen(m_device, kIOHIDOptionsTypeNone);
m_connected = ret == kIOReturnSuccess;
if (m_connected)
{
IOHIDDeviceScheduleWithRunLoop(m_device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
IOHIDDeviceRegisterInputReportCallback(m_device,
m_report_buffer.data() + 1,
MAX_PAYLOAD - 1,
&WiimoteDarwinHid::ReportCallback,
this);
IOHIDDeviceRegisterRemovalCallback(m_device, &WiimoteDarwinHid::RemoveCallback, this);
NOTICE_LOG(WIIMOTE, "Connected to Wiimote %i", m_index + 1);
}
else
{
ERROR_LOG(WIIMOTE, "Could not open IOHID Wiimote: %08x", ret);
}
return m_connected;
}
void WiimoteDarwinHid::DisconnectInternal()
{
IOHIDDeviceUnscheduleFromRunLoop(m_device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
IOWakeup();
IOReturn ret = IOHIDDeviceClose(m_device, kIOHIDOptionsTypeNone);
if (ret != kIOReturnSuccess)
ERROR_LOG(WIIMOTE, "Error closing IOHID Wiimote: %08x", ret);
if (!IsConnected())
return;
NOTICE_LOG(WIIMOTE, "Disconnecting Wiimote %i", m_index + 1);
m_buffered_reports.Clear();
m_connected = false;
}
bool WiimoteDarwinHid::IsConnected() const
{
return m_connected;
}
void WiimoteDarwinHid::IOWakeup()
{
m_interrupted.store(true);
CFRunLoopStop(CFRunLoopGetCurrent());
}
int WiimoteDarwinHid::IORead(u8* buf)
{
Report rpt;
m_interrupted.store(false);
while (m_buffered_reports.Empty() && !m_interrupted.load())
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
if (m_buffered_reports.Pop(rpt))
{
memcpy(buf, rpt.data(), rpt.size());
return rpt.size();
}
return -1;
}
int WiimoteDarwinHid::IOWrite(u8 const* buf, size_t len)
{
IOReturn ret = IOHIDDeviceSetReport(m_device, kIOHIDReportTypeOutput, buf[1], buf + 1, len - 1);
if (ret != kIOReturnSuccess)
{
ERROR_LOG(WIIMOTE, "Error writing to Wiimote: %08x", ret);
return 0;
}
return len;
}
void WiimoteDarwinHid::QueueBufferReport(int length)
{
Report rpt(m_report_buffer);
rpt[0] = 0xa1;
rpt.resize(length + 1);
m_buffered_reports.Push(std::move(rpt));
}
void WiimoteDarwinHid::ReportCallback(void* context, IOReturn result, void*, IOHIDReportType type, u32 report_id, u8* report, CFIndex report_length)
{
WiimoteDarwinHid* wm = static_cast<WiimoteDarwinHid*>(context);
report[0] = report_id;
wm->QueueBufferReport(report_length);
}
void WiimoteDarwinHid::RemoveCallback(void* context, IOReturn result, void*)
{
WiimoteDarwinHid* wm = static_cast<WiimoteDarwinHid*>(context);
wm->DisconnectInternal();
}
} // namespace
@implementation SearchBT

View File

@@ -16,6 +16,7 @@
// end hack
#import <IOBluetooth/IOBluetooth.h>
#include <IOKit/pwr_mgt/IOPMLib.h>
#include <IOKit/hid/IOHIDManager.h>
#elif defined(__linux__) && HAVE_BLUEZ
#include <bluetooth/bluetooth.h>
#endif

View File

@@ -333,7 +333,7 @@ unsigned int NetPlayServer::OnConnect(ENetPeer* socket)
// add client to the player list
{
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
m_players.insert(std::pair<PlayerId, Client>(*(PlayerId *)player.socket->data, player));
m_players.emplace(*(PlayerId *)player.socket->data, player);
UpdatePadMapping(); // sync pad mappings with everyone
UpdateWiimoteMapping();
}

View File

@@ -23,6 +23,11 @@ void Interpreter::bx(UGeckoInstruction _inst)
#endif*/
m_EndBlock = true;
if (NPC == PC && SConfig::GetInstance().bSkipIdle)
{
CoreTiming::Idle();
}
}
// bcx - ugly, straight from PPC manual equations :)
@@ -50,6 +55,23 @@ void Interpreter::bcx(UGeckoInstruction _inst)
}
m_EndBlock = true;
// this code trys to detect the most common idle loop:
// lwz r0, XXXX(r13)
// cmpXwi r0,0
// beq -8
if (NPC == PC - 8 && _inst.hex == 0x4182fff8 /* beq */ && SConfig::GetInstance().bSkipIdle)
{
if (PowerPC::HostRead_U32(PC - 8) >> 16 == 0x800D /* lwz */ )
{
u32 last_inst = PowerPC::HostRead_U32(PC - 4);
if (last_inst == 0x28000000 /* cmplwi */ || (last_inst == 0x2C000000 /* cmpwi */ && SConfig::GetInstance().bWii))
{
CoreTiming::Idle();
}
}
}
}
void Interpreter::bcctrx(UGeckoInstruction _inst)

View File

@@ -12,9 +12,6 @@
#include "Core/PowerPC/Gekko.h"
#include "Core/PowerPC/Interpreter/Interpreter.h"
#define MIN_SINGLE 0xc7efffffe0000000ull
#define MAX_SINGLE 0x47efffffe0000000ull
const u64 PPC_NAN_U64 = 0x7ff8000000000000ull;
const double PPC_NAN = *(double* const)&PPC_NAN_U64;
@@ -79,6 +76,13 @@ inline double Force25Bit(double d)
return x.d;
}
inline double MakeQuiet(double d)
{
MathUtil::IntDouble x(d);
x.i |= MathUtil::DOUBLE_QBIT;
return x.d;
}
// these functions allow globally modify operations behaviour
// also, these may be used to set flags like FR, FI, OX, UX
@@ -87,21 +91,43 @@ inline double NI_mul(double a, double b)
double t = a * b;
if (std::isnan(t))
{
if (std::isnan(a)) return a;
if (std::isnan(b)) return b;
if (std::isnan(a)) return MakeQuiet(a);
if (std::isnan(b)) return MakeQuiet(b);
SetFPException(FPSCR_VXIMZ);
return PPC_NAN;
}
return t;
}
inline double NI_div(double a, double b)
{
double t = a / b;
if (std::isnan(t))
{
if (std::isnan(a)) return MakeQuiet(a);
if (std::isnan(b)) return MakeQuiet(b);
if (b == 0.0)
{
SetFPException(FPSCR_ZX);
if (a == 0.0)
SetFPException(FPSCR_VXZDZ);
}
else if (std::isinf(a) && std::isinf(b))
{
SetFPException(FPSCR_VXIDI);
}
return PPC_NAN;
}
return t;
}
inline double NI_add(double a, double b)
{
double t = a + b;
if (std::isnan(t))
{
if (std::isnan(a)) return a;
if (std::isnan(b)) return b;
if (std::isnan(a)) return MakeQuiet(a);
if (std::isnan(b)) return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
return PPC_NAN;
}
@@ -113,8 +139,8 @@ inline double NI_sub(double a, double b)
double t = a - b;
if (std::isnan(t))
{
if (std::isnan(a)) return a;
if (std::isnan(b)) return b;
if (std::isnan(a)) return MakeQuiet(a);
if (std::isnan(b)) return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
return PPC_NAN;
}
@@ -129,16 +155,16 @@ inline double NI_madd(double a, double c, double b, bool negate = false)
double t = a * c;
if (std::isnan(t))
{
if (std::isnan(a)) return a;
if (std::isnan(b)) return b; // !
if (std::isnan(c)) return c;
if (std::isnan(a)) return MakeQuiet(a);
if (std::isnan(b)) return MakeQuiet(b); // !
if (std::isnan(c)) return MakeQuiet(c);
SetFPException(FPSCR_VXIMZ);
return PPC_NAN;
}
t += b;
if (std::isnan(t))
{
if (std::isnan(b)) return b;
if (std::isnan(b)) return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
return PPC_NAN;
}
@@ -150,9 +176,9 @@ inline double NI_msub(double a, double c, double b, bool negate = false)
double t = a * c;
if (std::isnan(t))
{
if (std::isnan(a)) return a;
if (std::isnan(b)) return b; // !
if (std::isnan(c)) return c;
if (std::isnan(a)) return MakeQuiet(a);
if (std::isnan(b)) return MakeQuiet(b); // !
if (std::isnan(c)) return MakeQuiet(c);
SetFPException(FPSCR_VXIMZ);
return PPC_NAN;
}
@@ -160,7 +186,7 @@ inline double NI_msub(double a, double c, double b, bool negate = false)
t -= b;
if (std::isnan(t))
{
if (std::isnan(b)) return b;
if (std::isnan(b)) return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
return PPC_NAN;
}

View File

@@ -351,38 +351,7 @@ void Interpreter::faddsx(UGeckoInstruction _inst)
void Interpreter::fdivx(UGeckoInstruction _inst)
{
double a = rPS0(_inst.FA);
double b = rPS0(_inst.FB);
if (a != a)
{
rPS0(_inst.FD) = a;
}
else if (b != b)
{
rPS0(_inst.FD) = b;
}
else
{
rPS0(_inst.FD) = ForceDouble(a / b);
if (b == 0.0)
{
if (a == 0.0)
{
SetFPException(FPSCR_VXZDZ);
rPS0(_inst.FD) = PPC_NAN;
}
SetFPException(FPSCR_ZX);
}
else
{
if (IsINF(a) && IsINF(b))
{
SetFPException(FPSCR_VXIDI);
rPS0(_inst.FD) = PPC_NAN;
}
}
}
rPS0(_inst.FD) = ForceDouble(NI_div(rPS0(_inst.FA), rPS0(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
// FR,FI,OX,UX???
@@ -391,41 +360,7 @@ void Interpreter::fdivx(UGeckoInstruction _inst)
}
void Interpreter::fdivsx(UGeckoInstruction _inst)
{
double a = rPS0(_inst.FA);
double b = rPS0(_inst.FB);
double res;
if (a != a)
{
res = a;
}
else if (b != b)
{
res = b;
}
else
{
res = ForceSingle(a / b);
if (b == 0.0)
{
if (a == 0.0)
{
SetFPException(FPSCR_VXZDZ);
res = PPC_NAN;
}
SetFPException(FPSCR_ZX);
}
else
{
if (IsINF(a) && IsINF(b))
{
SetFPException(FPSCR_VXIDI);
res = PPC_NAN;
}
}
}
rPS0(_inst.FD) = rPS1(_inst.FD) = res;
rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_div(rPS0(_inst.FA), rPS0(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)

View File

@@ -104,97 +104,8 @@ void Interpreter::ps_merge11(UGeckoInstruction _inst)
// From here on, the real deal.
void Interpreter::ps_div(UGeckoInstruction _inst)
{
u32 ex_mask = 0;
// PS0
{
double a = rPS0(_inst.FA);
double b = rPS0(_inst.FB);
double &res = rPS0(_inst.FD);
if (a != a)
{
res = a;
}
else if (b != b)
{
res = b;
}
else
{
if (b == 0.0)
{
ex_mask |= FPSCR_ZX;
if (rPS0(_inst.FA) == 0.0)
{
ex_mask |= FPSCR_VXZDZ;
res = PPC_NAN;
}
else
{
res = ForceSingle(a / b);
}
}
else
{
if (IsINF(a) && IsINF(b))
{
ex_mask |= FPSCR_VXIDI;
res = PPC_NAN;
}
else
{
res = ForceSingle(a / b);
}
}
}
}
// PS1
{
double a = rPS1(_inst.FA);
double b = rPS1(_inst.FB);
double &res = rPS1(_inst.FD);
if (a != a)
{
res = a;
}
else if (b != b)
{
res = b;
}
else
{
if (b == 0.0)
{
ex_mask |= FPSCR_ZX;
if (rPS0(_inst.FA) == 0.0)
{
ex_mask |= FPSCR_VXZDZ;
res = PPC_NAN;
}
else
{
res = ForceSingle(a / b);
}
}
else
{
if (IsINF(a) && IsINF(b))
{
ex_mask |= FPSCR_VXIDI;
res = PPC_NAN;
}
else
{
res = ForceSingle(a / b);
}
}
}
}
SetFPException(ex_mask);
rPS0(_inst.FD) = ForceSingle(NI_div(rPS0(_inst.FA), rPS0(_inst.FB)));
rPS1(_inst.FD) = ForceSingle(NI_div(rPS1(_inst.FA), rPS1(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)

View File

@@ -137,7 +137,7 @@ void Jit64::lXXx(UGeckoInstruction inst)
BitSet32 registersInUse = CallerSavedRegistersInUse();
ABI_PushRegistersAndAdjustStack(registersInUse, 0);
ABI_CallFunction((void *)&PowerPC::OnIdle);
ABI_CallFunction((void *)&CoreTiming::Idle);
ABI_PopRegistersAndAdjustStack(registersInUse, 0);

View File

@@ -119,13 +119,12 @@ void CommonAsmRoutines::GenFres()
MOV(32, R(RSCRATCH2), R(RSCRATCH_EXTRA));
AND(32, R(RSCRATCH_EXTRA), Imm32(0x7FF)); // exp
AND(32, R(RSCRATCH2), Imm32(0x800)); // sign
CMP(32, R(RSCRATCH_EXTRA), Imm32(895));
SUB(32, R(RSCRATCH_EXTRA), Imm32(895));
CMP(32, R(RSCRATCH_EXTRA), Imm32(1149 - 895));
// Take the complex path for very large/small exponents.
FixupBranch complex1 = J_CC(CC_L);
CMP(32, R(RSCRATCH_EXTRA), Imm32(1149));
FixupBranch complex2 = J_CC(CC_GE);
FixupBranch complex = J_CC(CC_AE); // if (exp < 895 || exp >= 1149)
SUB(32, R(RSCRATCH_EXTRA), Imm32(0x7FD));
SUB(32, R(RSCRATCH_EXTRA), Imm32(0x7FD - 895));
NEG(32, R(RSCRATCH_EXTRA));
OR(32, R(RSCRATCH_EXTRA), R(RSCRATCH2));
SHL(64, R(RSCRATCH_EXTRA), Imm8(52)); // vali = sign | exponent
@@ -154,8 +153,7 @@ void CommonAsmRoutines::GenFres()
OR(32, PPCSTATE(fpscr), Imm32(FPSCR_FX | FPSCR_ZX));
SetJumpTarget(skip_set_fx1);
SetJumpTarget(complex1);
SetJumpTarget(complex2);
SetJumpTarget(complex);
ABI_PushRegistersAndAdjustStack(QUANTIZED_REGS_TO_SAVE, 8);
ABI_CallFunction((void *)&MathUtil::ApproximateReciprocal);
ABI_PopRegistersAndAdjustStack(QUANTIZED_REGS_TO_SAVE, 8);

View File

@@ -2113,7 +2113,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, u32 exitAddress)
FixupBranch noidle = Jit->J_CC(CC_NZ);
RI.Jit->Cleanup(); // is it needed?
Jit->ABI_CallFunction((void *)&PowerPC::OnIdle);
Jit->ABI_CallFunction((void *)&CoreTiming::Idle);
Jit->MOV(32, PPCSTATE(pc), Imm32(ibuild->GetImmValue( getOp2(I) )));
Jit->WriteExceptionExit();

View File

@@ -51,10 +51,45 @@ void JitArm64::FallBackToInterpreter(UGeckoInstruction inst)
{
gpr.Flush(FlushMode::FLUSH_INTERPRETER, js.op);
fpr.Flush(FlushMode::FLUSH_INTERPRETER, js.op);
if (js.op->opinfo->flags & FL_ENDBLOCK)
{
// also flush the program counter
ARM64Reg WA = gpr.GetReg();
MOVI2R(WA, js.compilerPC);
STR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(pc));
ADD(WA, WA, 4);
STR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(npc));
gpr.Unlock(WA);
}
Interpreter::_interpreterInstruction instr = GetInterpreterOp(inst);
MOVI2R(W0, inst.hex);
MOVI2R(X30, (u64)instr);
BLR(X30);
if (js.op->opinfo->flags & FL_ENDBLOCK)
{
if (js.isLastInstruction)
{
ARM64Reg WA = gpr.GetReg();
LDR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(npc));
WriteExceptionExit(WA);
}
else
{
// only exit if ppcstate.npc was changed
ARM64Reg WA = gpr.GetReg();
LDR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(npc));
ARM64Reg WB = gpr.GetReg();
MOVI2R(WB, js.compilerPC + 4);
CMP(WB, WA);
gpr.Unlock(WB);
FixupBranch c = B(CC_EQ);
WriteExceptionExit(WA);
SetJumpTarget(c);
}
}
}
void JitArm64::HLEFunction(UGeckoInstruction inst)

View File

@@ -98,6 +98,7 @@ public:
void subfx(UGeckoInstruction inst);
void addcx(UGeckoInstruction inst);
void slwx(UGeckoInstruction inst);
void rlwimix(UGeckoInstruction inst);
// System Registers
void mtmsr(UGeckoInstruction inst);
@@ -113,7 +114,6 @@ public:
void mtspr(UGeckoInstruction inst);
// LoadStore
void icbi(UGeckoInstruction inst);
void lXX(UGeckoInstruction inst);
void stX(UGeckoInstruction inst);
void lmw(UGeckoInstruction inst);

View File

@@ -18,6 +18,7 @@ using namespace Arm64Gen;
void JitArm64::sc(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITBranchOff);
gpr.Flush(FlushMode::FLUSH_ALL);
fpr.Flush(FlushMode::FLUSH_ALL);
@@ -38,6 +39,7 @@ void JitArm64::sc(UGeckoInstruction inst)
void JitArm64::rfi(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITBranchOff);
gpr.Flush(FlushMode::FLUSH_ALL);
fpr.Flush(FlushMode::FLUSH_ALL);
@@ -78,6 +80,7 @@ void JitArm64::rfi(UGeckoInstruction inst)
void JitArm64::bx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITBranchOff);
gpr.Flush(FlushMode::FLUSH_ALL);
fpr.Flush(FlushMode::FLUSH_ALL);
@@ -115,6 +118,7 @@ void JitArm64::bx(UGeckoInstruction inst)
void JitArm64::bcx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITBranchOff);
ARM64Reg WA = gpr.GetReg();
FixupBranch pCTRDontBranch;
@@ -173,45 +177,42 @@ void JitArm64::bcx(UGeckoInstruction inst)
void JitArm64::bcctrx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITBranchOff);
// Rare condition seen in (just some versions of?) Nintendo's NES Emulator
// BO_2 == 001zy -> b if false
// BO_2 == 011zy -> b if true
FALLBACK_IF(!(inst.BO_2 & BO_DONT_CHECK_CONDITION));
// bcctrx doesn't decrement and/or test CTR
_assert_msg_(DYNA_REC, inst.BO_2 & BO_DONT_DECREMENT_FLAG, "bcctrx with decrement and test CTR option is invalid!");
if (inst.BO_2 & BO_DONT_CHECK_CONDITION)
// BO_2 == 1z1zz -> b always
//NPC = CTR & 0xfffffffc;
gpr.Flush(FlushMode::FLUSH_ALL);
fpr.Flush(FlushMode::FLUSH_ALL);
if (inst.LK_3)
{
// BO_2 == 1z1zz -> b always
//NPC = CTR & 0xfffffffc;
gpr.Flush(FlushMode::FLUSH_ALL);
fpr.Flush(FlushMode::FLUSH_ALL);
if (inst.LK_3)
{
ARM64Reg WB = gpr.GetReg();
u32 Jumpto = js.compilerPC + 4;
MOVI2R(WB, Jumpto);
STR(INDEX_UNSIGNED, WB, X29, PPCSTATE_OFF(spr[SPR_LR]));
gpr.Unlock(WB);
}
ARM64Reg WA = gpr.GetReg();
LDR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(spr[SPR_CTR]));
AND(WA, WA, 30, 29); // Wipe the bottom 2 bits.
WriteExitDestInR(WA);
}
else
{
// Rare condition seen in (just some versions of?) Nintendo's NES Emulator
// BO_2 == 001zy -> b if false
// BO_2 == 011zy -> b if true
_assert_msg_(DYNA_REC, false, "Haven't implemented rare form of bcctrx yet");
ARM64Reg WB = gpr.GetReg();
u32 Jumpto = js.compilerPC + 4;
MOVI2R(WB, Jumpto);
STR(INDEX_UNSIGNED, WB, X29, PPCSTATE_OFF(spr[SPR_LR]));
gpr.Unlock(WB);
}
ARM64Reg WA = gpr.GetReg();
LDR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(spr[SPR_CTR]));
AND(WA, WA, 30, 29); // Wipe the bottom 2 bits.
WriteExitDestInR(WA);
}
void JitArm64::bclrx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITBranchOff);
ARM64Reg WA = gpr.GetReg();
FixupBranch pCTRDontBranch;

View File

@@ -766,3 +766,79 @@ void JitArm64::slwx(UGeckoInstruction inst)
ComputeRC(gpr.R(a), 0);
}
}
void JitArm64::rlwimix(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
int a = inst.RA, s = inst.RS;
u32 mask = Helper_Mask(inst.MB, inst.ME);
if (gpr.IsImm(a) && gpr.IsImm(s))
{
u32 res = (gpr.GetImm(a) & ~mask) | (_rotl(gpr.GetImm(s), inst.SH) & mask);
gpr.SetImmediate(a, res);
if (inst.Rc)
ComputeRC(res, 0);
}
else
{
if (mask == 0 || (a == s && inst.SH == 0))
{
// Do Nothing
}
else if (mask == 0xFFFFFFFF)
{
if (inst.SH || a != s)
gpr.BindToRegister(a, a == s);
if (inst.SH)
ROR(gpr.R(a), gpr.R(s), 32 - inst.SH);
else if (a != s)
MOV(gpr.R(a), gpr.R(s));
}
else if (inst.SH == 0 && inst.MB <= inst.ME)
{
// No rotation
// No mask inversion
u32 lsb = 31 - inst.ME;
u32 width = inst.ME - inst.MB + 1;
gpr.BindToRegister(a, true);
ARM64Reg WA = gpr.GetReg();
UBFX(WA, gpr.R(s), lsb, width);
BFI(gpr.R(a), WA, lsb, width);
gpr.Unlock(WA);
}
else if (inst.SH && inst.MB <= inst.ME)
{
// No mask inversion
u32 lsb = 31 - inst.ME;
u32 width = inst.ME - inst.MB + 1;
gpr.BindToRegister(a, true);
ARM64Reg WA = gpr.GetReg();
ROR(WA, gpr.R(s), 32 - inst.SH);
UBFX(WA, WA, lsb, width);
BFI(gpr.R(a), WA, lsb, width);
gpr.Unlock(WA);
}
else
{
gpr.BindToRegister(a, true);
ARM64Reg WA = gpr.GetReg();
ARM64Reg WB = gpr.GetReg();
MOVI2R(WA, mask);
BIC(WB, gpr.R(a), WA);
AND(WA, WA, gpr.R(s), ArithOption(gpr.R(s), ST_ROR, 32 - inst.SH));
ORR(gpr.R(a), WB, WA);
gpr.Unlock(WA, WB);
}
if (inst.Rc)
ComputeRC(gpr.R(a), 0);
}
}

View File

@@ -18,15 +18,6 @@
using namespace Arm64Gen;
void JitArm64::icbi(UGeckoInstruction inst)
{
gpr.Flush(FlushMode::FLUSH_ALL);
fpr.Flush(FlushMode::FLUSH_ALL);
FallBackToInterpreter(inst);
WriteExit(js.compilerPC + 4);
}
void JitArm64::SafeLoadToReg(u32 dest, s32 addr, s32 offsetReg, u32 flags, s32 offset, bool update)
{
// We want to make sure to not get LR as a temp register
@@ -426,7 +417,7 @@ void JitArm64::lXX(UGeckoInstruction inst)
ARM64Reg WA = gpr.GetReg();
ARM64Reg XA = EncodeRegTo64(WA);
MOVI2R(XA, (u64)&PowerPC::OnIdle);
MOVI2R(XA, (u64)&CoreTiming::Idle);
BLR(XA);
gpr.Unlock(WA);

View File

@@ -48,8 +48,7 @@ FixupBranch JitArm64::JumpIfCRFieldBit(int field, int bit, bool jump_if_set)
void JitArm64::mtmsr(UGeckoInstruction inst)
{
INSTRUCTION_START
// Don't interpret this, if we do we get thrown out
//JITDISABLE(bJITSystemRegistersOff)
JITDISABLE(bJITSystemRegistersOff);
gpr.BindToRegister(inst.RS, true);
STR(INDEX_UNSIGNED, gpr.R(inst.RS), X29, PPCSTATE_OFF(msr));
@@ -143,6 +142,7 @@ void JitArm64::mtsrin(UGeckoInstruction inst)
void JitArm64::twx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITSystemRegistersOff);
s32 a = inst.RA;

View File

@@ -52,7 +52,7 @@ static GekkoOPTemplate primarytable[] =
{14, &JitArm64::arith_imm}, // addi
{15, &JitArm64::arith_imm}, // addis
{20, &JitArm64::FallBackToInterpreter}, // rlwimix
{20, &JitArm64::rlwimix}, // rlwimix
{21, &JitArm64::rlwinmx}, // rlwinmx
{23, &JitArm64::FallBackToInterpreter}, // rlwnmx
@@ -302,7 +302,7 @@ static GekkoOPTemplate table31[] =
{4, &JitArm64::twx}, // tw
{598, &JitArm64::DoNothing}, // sync
{982, &JitArm64::icbi}, // icbi
{982, &JitArm64::FallBackToInterpreter}, // icbi
// Unused instructions on GC
{310, &JitArm64::FallBackToInterpreter}, // eciwx

View File

@@ -136,7 +136,7 @@ using namespace Gen;
{
for (const auto& e : b.linkData)
{
links_to.insert(std::pair<u32, int>(e.exitAddress, block_num));
links_to.emplace(e.exitAddress, block_num);
}
LinkBlock(block_num);

View File

@@ -203,6 +203,12 @@ namespace JitInterface
bool HandleFault(uintptr_t access_address, SContext* ctx)
{
// Prevent nullptr dereference on a crash with no JIT present
if (!jit)
{
return false;
}
return jit->HandleFault(access_address, ctx);
}

View File

@@ -529,11 +529,6 @@ void CheckBreakPoints()
}
}
void OnIdle()
{
CoreTiming::Idle();
}
} // namespace

View File

@@ -163,8 +163,6 @@ volatile CPUState *GetStatePtr(); // this oddity is here instead of an extern d
u32 CompactCR();
void ExpandCR(u32 cr);
void OnIdle();
void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst);
// Easy register access macros.

View File

@@ -257,9 +257,12 @@ static std::map<double, int> GetSavedStates()
if (ReadHeader(filename, header))
{
double d = Common::Timer::GetDoubleTime() - header.time;
// increase time until unique value is obtained
while (m.find(d) != m.end()) d += .001;
m.insert(std::pair<double,int>(d, i));
while (m.find(d) != m.end())
d += .001;
m.emplace(d, i);
}
}
}

View File

@@ -467,7 +467,7 @@ void CVolumeDirectory::WriteEntry(const File::FSTEntry& entry, u32& fstOffset, u
// write entry to virtual disk
_dbg_assert_(DVDINTERFACE, m_virtualDisk.find(dataOffset) == m_virtualDisk.end());
m_virtualDisk.insert(make_pair(dataOffset, entry.physicalName));
m_virtualDisk.emplace(dataOffset, entry.physicalName);
// 4 byte aligned
dataOffset = ROUND_UP(dataOffset + entry.size, 0x8000ull);

View File

@@ -17,6 +17,7 @@
#include "Common/CommonTypes.h"
#include "Common/StringUtil.h"
#include "Core/ActionReplay.h"
#include "Core/Core.h"
#include "Core/HW/Memmap.h"
#include "DolphinWX/WxUtils.h"
#include "DolphinWX/Cheats/CheatSearchTab.h"
@@ -125,7 +126,7 @@ CheatSearchTab::CheatSearchTab(wxWindow* const parent)
void CheatSearchTab::StartNewSearch(wxCommandEvent& WXUNUSED(event))
{
const u8* const memptr = Memory::m_pRAM;
if (memptr == nullptr)
if (!Core::IsRunningAndStarted())
{
WxUtils::ShowErrorDialog(_("A game is not currently running."));
return;
@@ -157,7 +158,7 @@ void CheatSearchTab::StartNewSearch(wxCommandEvent& WXUNUSED(event))
void CheatSearchTab::FilterCheatSearchResults(wxCommandEvent&)
{
const u8* const memptr = Memory::m_pRAM;
if (memptr == nullptr)
if (!Core::IsRunningAndStarted())
{
WxUtils::ShowErrorDialog(_("A game is not currently running."));
return;

View File

@@ -87,13 +87,13 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer()
// Create an ID for the config button.
const wxWindowID button_id = wxWindow::NewControlId();
m_gc_port_config_ids.insert(std::make_pair(button_id, i));
m_gc_port_config_ids.emplace(button_id, i);
gamecube_configure_bt[i] = new wxButton(this, button_id, _("Configure"), wxDefaultPosition, wxSize(100, 25));
gamecube_configure_bt[i]->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnGameCubeConfigButton, this);
// Create a control ID for the choice boxes on the fly.
const wxWindowID choice_id = wxWindow::NewControlId();
m_gc_port_choice_ids.insert(std::make_pair(choice_id, i));
m_gc_port_choice_ids.emplace(choice_id, i);
// Only add AM-Baseboard to the first pad.
if (i == 0)
@@ -223,10 +223,10 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer()
// reserve four ids, so that we can calculate the index from the ids later on
// Stupid wx 2.8 doesn't support reserving sequential IDs, so we need to do that more complicated..
int source_ctrl_id = wxWindow::NewControlId();
m_wiimote_index_from_ctrl_id.insert(std::pair<wxWindowID, unsigned int>(source_ctrl_id, i));
m_wiimote_index_from_ctrl_id.emplace(source_ctrl_id, i);
int config_bt_id = wxWindow::NewControlId();
m_wiimote_index_from_conf_bt_id.insert(std::pair<wxWindowID, unsigned int>(config_bt_id, i));
m_wiimote_index_from_conf_bt_id.emplace(config_bt_id, i);
wiimote_label[i] = new wxStaticText(this, wxID_ANY, wiimote_str);
wiimote_source_ch[i] = new wxChoice(this, source_ctrl_id, wxDefaultPosition, wxDefaultSize, src_choices.size(), src_choices.data());
@@ -284,7 +284,7 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateBalanceBoardSizer()
wxFlexGridSizer* const bb_sizer = new wxFlexGridSizer(1, 5, 5);
int source_ctrl_id = wxWindow::NewControlId();
m_wiimote_index_from_ctrl_id.insert(std::pair<wxWindowID, unsigned int>(source_ctrl_id, WIIMOTE_BALANCE_BOARD));
m_wiimote_index_from_ctrl_id.emplace(source_ctrl_id, WIIMOTE_BALANCE_BOARD);
static const std::array<wxString, 2> src_choices = {{
_("None"), _("Real Balance Board")

View File

@@ -776,8 +776,8 @@ void TASInputDlg::GetValues(GCPadStatus* PadStatus)
PadStatus->stickY = m_main_stick.y_cont.value;
PadStatus->substickX = m_c_stick.x_cont.value;
PadStatus->substickY = m_c_stick.y_cont.value;
PadStatus->triggerLeft = m_l.checkbox->GetValue() ? 255 : m_l_cont.slider->GetValue();
PadStatus->triggerRight = m_r.checkbox->GetValue() ? 255 : m_r_cont.slider->GetValue();
PadStatus->triggerLeft = m_l.checkbox->GetValue() ? 255 : m_l_cont.value;
PadStatus->triggerRight = m_r.checkbox->GetValue() ? 255 : m_r_cont.value;
for (unsigned int i = 0; i < ArraySize(m_buttons); ++i)
{

View File

@@ -117,7 +117,7 @@ static wxString internal_res_desc = _("Specifies the resolution used to render a
static wxString efb_access_desc = _("Ignore any requests of the CPU to read from or write to the EFB.\nImproves performance in some games, but might disable some gameplay-related features or graphical effects.\n\nIf unsure, leave this unchecked.");
static wxString efb_fast_access_desc = _("Use a fast efb caching method to speed up access. This method is inaccurate but will make games run faster and efb reads and writes will still work.");
static wxString efb_emulate_format_changes_desc = _("Ignore any changes to the EFB format.\nImproves performance in many games without any negative effect. Causes graphical defects in a small number of other games though.\n\nIf unsure, leave this checked.");
static wxString skip_efb_copy_to_ram_desc = _("Skip GPU synchronizing on EFB copies. Causes graphical defects in a small number of games.\n\nIf unsure, leave this checked.");
static wxString skip_efb_copy_to_ram_desc = wxTRANSLATE("Stores EFB Copies exclusively on the GPU, bypassing system memory. Causes graphical defects in a small number of games.\n\nEnabled = EFB Copies to Texture\nDisabled = EFB Copies to RAM (and Texture)\n\nIf unsure, leave this checked.");
static wxString stc_desc = _("The safer you adjust this, the less likely the emulator will be missing any texture updates from RAM.\n\nIf unsure, use the rightmost value.");
static wxString bbox_desc = _("Selects wish implementation is used to emulate Bounding Box. By Default GPU will be used if supported.");
static wxString wireframe_desc = _("Render the scene as a wireframe.\n\nIf unsure, leave this unchecked.");

View File

@@ -37,6 +37,11 @@ elseif(ANDROID)
ControllerInterface/Android/Android.cpp)
endif()
if(LIBEVDEV_FOUND AND LIBUDEV_FOUND)
set(SRCS ${SRCS} ControllerInterface/evdev/evdev.cpp)
set(LIBS ${LIBS} ${LIBEVDEV_LIBRARY} ${LIBUDEV_LIBRARY})
endif()
if(SDL_FOUND OR SDL2_FOUND)
set(SRCS ${SRCS} ControllerInterface/SDL/SDL.cpp)
if (SDL2_FOUND)

View File

@@ -26,6 +26,9 @@
#ifdef CIFACE_USE_ANDROID
#include "InputCommon/ControllerInterface/Android/Android.h"
#endif
#ifdef CIFACE_USE_EVDEV
#include "InputCommon/ControllerInterface/evdev/evdev.h"
#endif
using namespace ciface::ExpressionParser;
@@ -69,6 +72,9 @@ void ControllerInterface::Initialize(void* const hwnd)
#ifdef CIFACE_USE_ANDROID
ciface::Android::Init(m_devices);
#endif
#ifdef CIFACE_USE_EVDEV
ciface::evdev::Init(m_devices);
#endif
m_is_init = true;
}

View File

@@ -35,6 +35,9 @@
#if defined(HAVE_SDL) && HAVE_SDL
#define CIFACE_USE_SDL
#endif
#if defined(HAVE_LIBEVDEV) && defined(HAVE_LIBUDEV)
#define CIFACE_USE_EVDEV
#endif
//
// ControllerInterface

View File

@@ -0,0 +1,270 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <libudev.h>
#include <unistd.h>
#include "Common/Logging/Log.h"
#include "InputCommon/ControllerInterface/evdev/evdev.h"
namespace ciface
{
namespace evdev
{
void Init(std::vector<Core::Device*> &controllerDevices)
{
int num_controllers = 0;
// We use Udev to find any devices. In the future this will allow for hotplugging.
// But for now it is essentially iterating over /dev/input/event0 to event31. However if the
// naming scheme is ever updated in the future, this *should* be forwards compatable.
struct udev* udev = udev_new();
_assert_msg_(PAD, udev != 0, "Couldn't initilize libudev.");
// List all input devices
udev_enumerate* enumerate = udev_enumerate_new(udev);
udev_enumerate_add_match_subsystem(enumerate, "input");
udev_enumerate_scan_devices(enumerate);
udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
// Iterate over all input devices
udev_list_entry* dev_list_entry;
udev_list_entry_foreach(dev_list_entry, devices)
{
const char* path = udev_list_entry_get_name(dev_list_entry);
udev_device* dev = udev_device_new_from_syspath(udev, path);
const char* devnode = udev_device_get_devnode(dev);
// We only care about devices which we have read/write access to.
if (access(devnode, W_OK) == 0)
{
// Unfortunately udev gives us no way to filter out the non event device interfaces.
// So we open it and see if it works with evdev ioctls or not.
evdevDevice* input = new evdevDevice(devnode, num_controllers);
if (input->IsInteresting())
{
controllerDevices.push_back(input);
num_controllers++;
}
else
{
// Either it wasn't a evdev device, or it didn't have at least 8 buttons or two axis.
delete input;
}
}
udev_device_unref(dev);
}
udev_enumerate_unref(enumerate);
udev_unref(udev);
}
evdevDevice::evdevDevice(const std::string &devnode, int id) : m_devfile(devnode), m_id(id)
{
// The device file will be read on one of the main threads, so we open in non-blocking mode.
m_fd = open(devnode.c_str(), O_RDWR|O_NONBLOCK);
int ret = libevdev_new_from_fd(m_fd, &m_dev);
if (ret != 0)
{
// This useally fails because the device node isn't an evdev device, such as /dev/input/js0
m_initialized = false;
close(m_fd);
return;
}
m_name = libevdev_get_name(m_dev);
// Controller buttons (and keyboard keys)
int num_buttons = 0;
for (int key = 0; key < KEY_MAX; key++)
if (libevdev_has_event_code(m_dev, EV_KEY, key))
AddInput(new Button(num_buttons++, key, m_dev));
// Absolute axis (thumbsticks)
int num_axis = 0;
for (int axis = 0; axis < 0x100; axis++)
if (libevdev_has_event_code(m_dev, EV_ABS, axis))
{
AddAnalogInputs(new Axis(num_axis, axis, false, m_dev),
new Axis(num_axis, axis, true, m_dev));
num_axis++;
}
// Force feedback
if (libevdev_has_event_code(m_dev, EV_FF, FF_PERIODIC))
{
for (auto type : {FF_SINE, FF_SQUARE, FF_TRIANGLE, FF_SAW_UP, FF_SAW_DOWN})
if (libevdev_has_event_code(m_dev, EV_FF, type))
AddOutput(new ForceFeedback(type, m_dev));
}
if (libevdev_has_event_code(m_dev, EV_FF, FF_RUMBLE))
{
AddOutput(new ForceFeedback(FF_RUMBLE, m_dev));
}
// TODO: Add leds as output devices
m_initialized = true;
m_interesting = num_axis >= 2 || num_buttons >= 8;
}
evdevDevice::~evdevDevice()
{
if (m_initialized)
{
libevdev_free(m_dev);
close(m_fd);
}
}
void evdevDevice::UpdateInput()
{
// Run through all evdev events
// libevdev will keep track of the actual controller state internally which can be queried
// later with libevdev_fetch_event_value()
input_event ev;
int rc = LIBEVDEV_READ_STATUS_SUCCESS;
do
{
if (rc == LIBEVDEV_READ_STATUS_SYNC)
rc = libevdev_next_event(m_dev, LIBEVDEV_READ_FLAG_SYNC, &ev);
else
rc = libevdev_next_event(m_dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
} while (rc >= 0);
}
std::string evdevDevice::Button::GetName() const
{
// Buttons below 0x100 are mostly keyboard keys, and the names make sense
if (m_code < 0x100)
{
const char* name = libevdev_event_code_get_name(EV_KEY, m_code);
if (name)
return std::string(name);
}
// But controllers use codes above 0x100, and the standard label often doesn't match.
// We are better off with Button 0 and so on.
return "Button " + std::to_string(m_index);
}
ControlState evdevDevice::Button::GetState() const
{
int value = 0;
libevdev_fetch_event_value(m_dev, EV_KEY, m_code, &value);
return value;
}
evdevDevice::Axis::Axis(u8 index, u16 code, bool upper, libevdev* dev) :
m_code(code), m_index(index), m_upper(upper), m_dev(dev)
{
m_min = libevdev_get_abs_minimum(m_dev, m_code);
m_range = libevdev_get_abs_maximum(m_dev, m_code) + abs(m_min);
}
std::string evdevDevice::Axis::GetName() const
{
return "Axis " + std::to_string(m_index) + (m_upper ? "+" : "-");
}
ControlState evdevDevice::Axis::GetState() const
{
int value = 0;
libevdev_fetch_event_value(m_dev, EV_ABS, m_code, &value);
// Value from 0.0 to 1.0
ControlState fvalue = double(value - m_min) / double(m_range);
// Split into two axis, each covering half the range from 0.0 to 1.0
if (m_upper)
return std::max(0.0, fvalue - 0.5) * 2.0;
else
return (0.5 - std::min(0.5, fvalue)) * 2.0;
}
std::string evdevDevice::ForceFeedback::GetName() const
{
// We have some default names.
switch (m_type)
{
case FF_SINE:
return "Sine";
case FF_TRIANGLE:
return "Triangle";
case FF_SQUARE:
return "Square";
case FF_RUMBLE:
return "LeftRight";
default:
{
const char* name = libevdev_event_code_get_name(EV_FF, m_type);
if (name)
return std::string(name);
return "Unknown";
}
}
}
void evdevDevice::ForceFeedback::SetState(ControlState state)
{
// libevdev doesn't have nice helpers for forcefeedback
// we will use the file descriptors directly.
if (state > 0) // Upload and start an effect.
{
ff_effect effect;
effect.id = -1;
effect.direction = 0; // down
effect.replay.length = 500; // 500ms
effect.replay.delay = 0;
effect.trigger.button = 0; // don't trigger on button press
effect.trigger.interval = 0;
// This is the the interface that XInput uses, with 2 motors of differing sizes/frequencies that
// are controlled seperatally
if (m_type == FF_RUMBLE)
{
effect.type = FF_RUMBLE;
// max ranges tuned to 'feel' similar in magnitude to triangle/sine on xbox360 controller
effect.u.rumble.strong_magnitude = u16(state * 0x4000);
effect.u.rumble.weak_magnitude = u16(state * 0xFFFF);
}
else // FF_PERIODIC, a more generic interface.
{
effect.type = FF_PERIODIC;
effect.u.periodic.waveform = m_type;
effect.u.periodic.phase = 0x7fff; // 180 degrees
effect.u.periodic.offset = 0;
effect.u.periodic.period = 10;
effect.u.periodic.magnitude = s16(state * 0x7FFF);
effect.u.periodic.envelope.attack_length = 0; // no attack
effect.u.periodic.envelope.attack_level = 0;
effect.u.periodic.envelope.fade_length = 0;
effect.u.periodic.envelope.fade_level = 0;
}
ioctl(m_fd, EVIOCSFF, &effect);
m_id = effect.id;
input_event play;
play.type = EV_FF;
play.code = m_id;
play.value = 1;
write(m_fd, (const void*) &play, sizeof(play));
}
else if (m_id != -1) // delete the effect (which also stops it)
{
ioctl(m_id, EVIOCRMFF, m_id);
}
}
}
}

View File

@@ -0,0 +1,86 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <string>
#include <vector>
#include <libevdev/libevdev.h>
#include "InputCommon/ControllerInterface/Device.h"
namespace ciface
{
namespace evdev
{
void Init(std::vector<Core::Device*>& devices);
class evdevDevice : public Core::Device
{
private:
class Button : public Core::Device::Input
{
public:
std::string GetName() const override;
Button(u8 index, u16 code, libevdev* dev) : m_index(index), m_code(code), m_dev(dev) {}
ControlState GetState() const override;
private:
const u8 m_index;
const u16 m_code;
libevdev* m_dev;
};
class Axis : public Core::Device::Input
{
public:
std::string GetName() const override;
Axis(u8 index, u16 code, bool upper, libevdev* dev);
ControlState GetState() const override;
private:
const u16 m_code;
const u8 m_index;
const bool m_upper;
int m_range;
int m_min;
libevdev* m_dev;
};
class ForceFeedback : public Core::Device::Output
{
public:
std::string GetName() const override;
ForceFeedback(u16 type, libevdev* dev) : m_type(type), m_id(-1) { m_fd = libevdev_get_fd(dev); }
void SetState(ControlState state) override;
private:
const u16 m_type;
int m_fd;
int m_id;
};
public:
void UpdateInput() override;
evdevDevice(const std::string &devnode, int id);
~evdevDevice();
std::string GetName() const override { return m_name; }
int GetId() const override { return m_id; }
std::string GetSource() const override { return "evdev"; }
bool IsInteresting() const { return m_initialized && m_interesting; }
private:
const std::string m_devfile;
int m_fd;
libevdev* m_dev;
std::string m_name;
const int m_id;
bool m_initialized;
bool m_interesting;
};
}
}

View File

@@ -351,9 +351,12 @@ ID3D11SamplerState* StateCache::Get(SamplerState state)
ID3D11SamplerState* res = nullptr;
HRESULT hr = D3D::device->CreateSamplerState(&sampdc, &res);
if (FAILED(hr)) PanicAlert("Fail %s %d\n", __FILE__, __LINE__);
D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "sampler state used to emulate the GX pipeline");
m_sampler.insert(std::make_pair(state.packed, std::move(D3D::SamplerStatePtr(res))));
if (SUCCEEDED(hr))
D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "sampler state used to emulate the GX pipeline");
else
PanicAlert("Fail %s %d\n", __FILE__, __LINE__);
m_sampler.emplace(state.packed, std::move(D3D::SamplerStatePtr(res)));
return res;
}
@@ -430,9 +433,12 @@ ID3D11BlendState* StateCache::Get(BlendState state)
ID3D11BlendState* res = nullptr;
HRESULT hr = D3D::device->CreateBlendState(&blenddc, &res);
if (FAILED(hr)) PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__);
D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "blend state used to emulate the GX pipeline");
m_blend.insert(std::make_pair(state.packed, std::move(D3D::BlendStatePtr(res))));
if (SUCCEEDED(hr))
D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "blend state used to emulate the GX pipeline");
else
PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__);
m_blend.emplace(state.packed, std::move(D3D::BlendStatePtr(res)));
return res;
}
@@ -451,9 +457,12 @@ ID3D11RasterizerState* StateCache::Get(RasterizerState state)
ID3D11RasterizerState* res = nullptr;
HRESULT hr = D3D::device->CreateRasterizerState(&rastdc, &res);
if (FAILED(hr)) PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__);
D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "rasterizer state used to emulate the GX pipeline");
m_raster.insert(std::make_pair(state.packed, std::move(D3D::RasterizerStatePtr(res))));
if (SUCCEEDED(hr))
D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "rasterizer state used to emulate the GX pipeline");
else
PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__);
m_raster.emplace(state.packed, std::move(D3D::RasterizerStatePtr(res)));
return res;
}
@@ -502,10 +511,11 @@ ID3D11DepthStencilState* StateCache::Get(ZMode state)
ID3D11DepthStencilState* res = nullptr;
HRESULT hr = D3D::device->CreateDepthStencilState(&depthdc, &res);
if (SUCCEEDED(hr)) D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "depth-stencil state used to emulate the GX pipeline");
else PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__);
m_depth.insert(std::make_pair(state.hex, std::move(D3D::DepthStencilStatePtr(res))));
if (SUCCEEDED(hr))
D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "depth-stencil state used to emulate the GX pipeline");
else
PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__);
m_depth.emplace(state.hex, std::move(D3D::DepthStencilStatePtr(res)));
return res;
}

View File

@@ -103,7 +103,7 @@ namespace DriverDetails
(bug.m_versionstart <= m_version || bug.m_versionstart == -1) &&
(bug.m_versionend > m_version || bug.m_versionend == -1)
)
m_bugs.insert(std::make_pair(bug.m_bug, bug));
m_bugs.emplace(bug.m_bug, bug);
}
}

View File

@@ -138,7 +138,7 @@ void HiresTexture::Update()
{
HiresTextureCacheItem item(min_item_size);
item[level] = Pair;
s_textureMap.insert(HiresTextureCache::value_type(FileName, item));
s_textureMap.emplace(FileName, item);
}
else
{
@@ -318,7 +318,7 @@ std::string HiresTexture::GenBaseName(
}
newitem[level] = std::pair<std::string, bool>(dst, convert_iter->second[level].second);
}
s_textureMap.insert(HiresTextureCache::value_type(fullname, newitem));
s_textureMap.emplace(fullname, newitem);
}
else
{

View File

@@ -73,7 +73,7 @@ void ClearMessages()
// On-Screen Display Callbacks
void AddCallback(CallbackType type, Callback cb)
{
s_callbacks.insert(std::pair<CallbackType, Callback>(type, cb));
s_callbacks.emplace(type, cb);
}
void DoCallbacks(CallbackType type)

View File

@@ -586,7 +586,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
g_texture_cache->LoadLut(tlutfmt, &texMem[tlutaddr], palette_size);
}
textures_by_address.insert(TexCache::value_type((u64)address, decoded_entry));
textures_by_address.emplace((u64)address, decoded_entry);
// If supported palettize, if not return the original entry
if (decoded_entry->PalettizeFromBase(entry))
@@ -644,7 +644,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
HiresTexPool::iterator hriter = hires_texture_pool.find(basename);
if (hriter != hires_texture_pool.end())
{
textures_by_address.insert(TexCache::value_type(address, hriter->second));
textures_by_address.emplace(address, hriter->second);
return ReturnEntry(stage, hriter->second);
}
hires_tex = HiresTexture::Search(
@@ -691,11 +691,11 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
TCacheEntryBase* entry = AllocateTexture(config);
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
iter = textures_by_address.insert(TexCache::value_type((u64)address, entry));
iter = textures_by_address.emplace((u64)address, entry);
if (g_ActiveConfig.iSafeTextureCache_ColorSamples == 0 ||
std::max(texture_size, palette_size) <= (u32)g_ActiveConfig.iSafeTextureCache_ColorSamples * 8)
{
entry->textures_by_hash_iter = textures_by_hash.insert(TexCache::value_type(full_hash, entry));
entry->textures_by_hash_iter = textures_by_hash.emplace(full_hash, entry);
}
entry->SetGeneralParameters(address, texture_size, full_format);
@@ -1093,7 +1093,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, u32 dstFormat, PEContr
entry->copyMipMapStrideChannels = bpmem.copyMipMapStrideChannels;
entry->FromRenderTarget(srcFormat, srcRect, isIntensity, scaleByHalf, cbufid, colmat);
textures_by_address.insert(TexCache::value_type(dstAddr, entry));
textures_by_address.emplace(dstAddr, entry);
}
TextureCache::TCacheEntryBase* TextureCache::AllocateTexture(const TCacheEntryConfig& config)
@@ -1130,7 +1130,7 @@ TextureCache::TexCache::iterator TextureCache::FreeTexture(TexCache::iterator it
}
else
{
texture_pool.insert(TexPool::value_type(entry->config, entry));
texture_pool.emplace(entry->config, entry);
}
return textures_by_address.erase(iter);
}