mirror of
https://github.com/project-slippi/Ishiiruka.git
synced 2025-10-06 00:12:42 +02:00
Merge latest master changes
This commit is contained in:
@@ -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)
|
||||
|
33
CMakeTests/FindLibevdev.cmake
Normal file
33
CMakeTests/FindLibevdev.cmake
Normal 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 )
|
28
CMakeTests/FindLibudev.cmake
Normal file
28
CMakeTests/FindLibudev.cmake
Normal 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 )
|
@@ -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>
|
||||
|
@@ -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.
@@ -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.
|
||||
|
@@ -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
|
||||
|
@@ -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.
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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.
|
||||
|
@@ -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]
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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()
|
||||
|
@@ -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>
|
@@ -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"/>
|
||||
|
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<transitionSet>
|
||||
<changeImageTransform/>
|
||||
</transitionSet>
|
@@ -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>
|
||||
|
@@ -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()
|
||||
|
@@ -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);
|
||||
|
@@ -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.
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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>
|
||||
|
@@ -628,6 +628,7 @@ void SConfig::LoadDefaults()
|
||||
bJITIntegerOff = false;
|
||||
bJITPairedOff = false;
|
||||
bJITSystemRegistersOff = false;
|
||||
bJITBranchOff = false;
|
||||
|
||||
m_strName = "NONE";
|
||||
m_strUniqueID = "00000000";
|
||||
|
@@ -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);
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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();
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -529,11 +529,6 @@ void CheckBreakPoints()
|
||||
}
|
||||
}
|
||||
|
||||
void OnIdle()
|
||||
{
|
||||
CoreTiming::Idle();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
|
@@ -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.
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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")
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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.");
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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
|
||||
|
270
Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp
Normal file
270
Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
86
Source/Core/InputCommon/ControllerInterface/evdev/evdev.h
Normal file
86
Source/Core/InputCommon/ControllerInterface/evdev/evdev.h
Normal 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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
}
|
Reference in New Issue
Block a user