Merge branch 'master' into android-new-control-input-overlay
Conflicts: Source/Android/res/values-ja/strings.xml Source/Android/res/values/strings.xml Source/Android/src/org/dolphinemu/dolphinemu/AboutFragment.java Source/Android/src/org/dolphinemu/dolphinemu/emulation/EmulationActivity.java Source/Android/src/org/dolphinemu/dolphinemu/folderbrowser/FolderBrowser.java Source/Android/src/org/dolphinemu/dolphinemu/gamelist/GameListActivity.java Source/Android/src/org/dolphinemu/dolphinemu/settings/video/VideoSettingsFragment.java
This commit is contained in:
@@ -8,8 +8,12 @@
|
||||
|
||||
<!-- Save State Slots -->
|
||||
<item
|
||||
android:id="@+id/saveStateRoot"
|
||||
android:id="@+id/takeScreenshot"
|
||||
android:showAsAction="ifRoom"
|
||||
android:title="@string/overlay_screenshot"/>
|
||||
<item
|
||||
android:id="@+id/saveStateRoot"
|
||||
android:showAsAction="never"
|
||||
android:title="@string/overlay_savestate">
|
||||
<menu>
|
||||
<item android:id="@+id/saveSlot1"
|
||||
@@ -32,7 +36,7 @@
|
||||
<!-- Load State Slots -->
|
||||
<item
|
||||
android:id="@+id/loadStateRoot"
|
||||
android:showAsAction="ifRoom"
|
||||
android:showAsAction="never"
|
||||
android:title="@string/overlay_loadstate">
|
||||
<menu>
|
||||
<item android:id="@+id/loadSlot1"
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<!-- About Fragment -->
|
||||
<string name="build_revision">ビルドのバージョン</string>
|
||||
<string name="supports_gles3">サポートのOpenGL ES 3</string>
|
||||
<string name="supports_neon">サポートのNEON</string>
|
||||
|
||||
<!-- Folder Browser -->
|
||||
<string name="current_dir">現在のディレクトリ: %1$s</string>
|
||||
@@ -25,12 +26,17 @@
|
||||
<string name="settings">設定</string>
|
||||
<string name="about">について</string>
|
||||
|
||||
<!-- Game List Activity - Device Compatibility AlertDialog -->
|
||||
<string name="device_compat_warning">デバイスの互換性の警告</string>
|
||||
<string name="device_compat_warning_msg">この電話は、NEON拡張をサポートしていません。 おそらくDolphinを実行することはできません。\nあなたはとにかくそれを実行してみますか?</string>
|
||||
|
||||
<!-- Game List Fragment -->
|
||||
<string name="file_clicked">クリックされたファイル: %1$s</string>
|
||||
|
||||
<!-- Emulation Window Overlay -->
|
||||
<string name="enable_input_overlay">入力オーバーレイを有効</string>
|
||||
<string name="disable_input_overlay">入力オーバーレイを無効</string>
|
||||
<string name="overlay_screenshot">スクリーンショットを撮る</string>
|
||||
<string name="overlay_savestate">ステートセーブ</string>
|
||||
<string name="overlay_loadstate">ステートロード</string>
|
||||
<string name="overlay_exit_emulation">終了</string>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<!-- About Fragment -->
|
||||
<string name="build_revision">Build Revision</string>
|
||||
<string name="supports_gles3">Supports OpenGL ES 3</string>
|
||||
<string name="supports_neon">Supports NEON</string>
|
||||
|
||||
<!-- Folder Browser -->
|
||||
<string name="current_dir">Current Dir: %1$s</string>
|
||||
@@ -25,12 +26,17 @@
|
||||
<string name="settings">Settings</string>
|
||||
<string name="about">About</string>
|
||||
|
||||
<!-- Game List Activity - Device Compatibility AlertDialog -->
|
||||
<string name="device_compat_warning">Device Compatibility Warning</string>
|
||||
<string name="device_compat_warning_msg">Your phone doesn\'t support NEON which makes it incapable of running Dolphin Mobile?\nDo you want to try anyway?</string>
|
||||
|
||||
<!-- Game List Fragment -->
|
||||
<string name="file_clicked">File clicked: %1$s</string>
|
||||
|
||||
<!-- Emulation Overlay -->
|
||||
<string name="enable_input_overlay">Enable Input Overlay</string>
|
||||
<string name="disable_input_overlay">Disable Input Overlay</string>
|
||||
<string name="overlay_screenshot">Take Screenshot</string>
|
||||
<string name="overlay_savestate">Save State</string>
|
||||
<string name="overlay_loadstate">Load State</string>
|
||||
<string name="overlay_exit_emulation">Exit</string>
|
||||
|
||||
@@ -29,21 +29,21 @@ public final class AboutFragment extends ListFragment
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
View rootView = inflater.inflate(R.layout.gamelist_listview, container, false);
|
||||
ListView mMainList = (ListView) rootView.findViewById(R.id.gamelist);
|
||||
ListView rootView = (ListView) inflater.inflate(R.layout.gamelist_listview, container, false);
|
||||
|
||||
String yes = getString(R.string.yes);
|
||||
String no = getString(R.string.no);
|
||||
final String yes = getString(R.string.yes);
|
||||
final String no = getString(R.string.no);
|
||||
|
||||
List<AboutFragmentItem> Input = new ArrayList<AboutFragmentItem>();
|
||||
Input.add(new AboutFragmentItem(getString(R.string.build_revision), NativeLibrary.GetVersionString()));
|
||||
Input.add(new AboutFragmentItem(getString(R.string.supports_gles3), VideoSettingsFragment.SupportsGLES3() ? yes : no));
|
||||
Input.add(new AboutFragmentItem(getString(R.string.supports_neon), NativeLibrary.SupportsNEON() ? yes : no));
|
||||
|
||||
AboutFragmentAdapter adapter = new AboutFragmentAdapter(getActivity(), R.layout.about_layout, Input);
|
||||
mMainList.setAdapter(adapter);
|
||||
mMainList.setEnabled(false); // Makes the list view non-clickable.
|
||||
rootView.setAdapter(adapter);
|
||||
rootView.setEnabled(false); // Makes the list view non-clickable.
|
||||
|
||||
return mMainList;
|
||||
return rootView;
|
||||
}
|
||||
|
||||
// Represents an item in the AboutFragment.
|
||||
@@ -94,18 +94,17 @@ public final class AboutFragment extends ListFragment
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent)
|
||||
{
|
||||
View v = convertView;
|
||||
if (v == null)
|
||||
if (convertView == null)
|
||||
{
|
||||
LayoutInflater vi = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
v = vi.inflate(id, parent, false);
|
||||
LayoutInflater vi = LayoutInflater.from(ctx);
|
||||
convertView = vi.inflate(id, parent, false);
|
||||
}
|
||||
|
||||
final AboutFragmentItem item = items.get(position);
|
||||
if (item != null)
|
||||
{
|
||||
TextView title = (TextView) v.findViewById(R.id.AboutItemTitle);
|
||||
TextView subtitle = (TextView) v.findViewById(R.id.AboutItemSubTitle);
|
||||
TextView title = (TextView) convertView.findViewById(R.id.AboutItemTitle);
|
||||
TextView subtitle = (TextView) convertView.findViewById(R.id.AboutItemSubTitle);
|
||||
|
||||
if (title != null)
|
||||
title.setText(item.getTitle());
|
||||
@@ -114,7 +113,7 @@ public final class AboutFragment extends ListFragment
|
||||
subtitle.setText(item.getSubTitle());
|
||||
}
|
||||
|
||||
return v;
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,4 +86,9 @@ public final class DolphinEmulator extends Activity
|
||||
UserPreferences.LoadIniToPrefs(this);
|
||||
}
|
||||
}
|
||||
protected void onRestart()
|
||||
{
|
||||
super.onRestart();
|
||||
finish(); // If we are ever returning to this activity then we are exiting.
|
||||
}
|
||||
}
|
||||
@@ -152,6 +152,19 @@ public final class NativeLibrary
|
||||
*/
|
||||
public static native String GetVersionString();
|
||||
|
||||
/**
|
||||
* Returns if the phone supports NEON or not
|
||||
*
|
||||
* @return true if it supports NEON, false otherwise.
|
||||
*/
|
||||
public static native boolean SupportsNEON();
|
||||
|
||||
/**
|
||||
* Saves a screen capture of the game
|
||||
*
|
||||
*/
|
||||
public static native void SaveScreenShot();
|
||||
|
||||
/**
|
||||
* Saves a game state to the slot number.
|
||||
*
|
||||
|
||||
@@ -64,12 +64,14 @@ public final class EmulationActivity extends Activity
|
||||
//
|
||||
// Due to a bug in Adreno, it renders the screen rotated 90 degrees when using OpenGL
|
||||
// Flip the width and height when on Adreno to work around this.
|
||||
// This bug is fixed in Qualcomm driver v53
|
||||
// Mali isn't affected by this bug.
|
||||
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
if (sharedPrefs.getString("gpuPref", "Software Rendering").equals("OGL")
|
||||
&& VideoSettingsFragment.SupportsGLES3()
|
||||
&& VideoSettingsFragment.m_GLVendor != null
|
||||
&& VideoSettingsFragment.m_GLVendor.equals("Qualcomm"))
|
||||
&& VideoSettingsFragment.m_GLVendor.equals("Qualcomm")
|
||||
&& VideoSettingsFragment.m_QualcommVersion < 53.0f)
|
||||
NativeLibrary.SetDimensions((int)screenHeight, (int)screenWidth);
|
||||
else
|
||||
NativeLibrary.SetDimensions((int)screenWidth, (int)screenHeight);
|
||||
@@ -204,6 +206,11 @@ public final class EmulationActivity extends Activity
|
||||
return true;
|
||||
}
|
||||
|
||||
// Screenshot capturing
|
||||
case R.id.takeScreenshot:
|
||||
NativeLibrary.SaveScreenShot();
|
||||
return true;
|
||||
|
||||
// Save state slots
|
||||
case R.id.saveSlot1:
|
||||
NativeLibrary.SaveState(0);
|
||||
|
||||
@@ -37,16 +37,17 @@ import org.dolphinemu.dolphinemu.gamelist.GameListActivity;
|
||||
public final class FolderBrowser extends ListFragment
|
||||
{
|
||||
private FolderBrowserAdapter adapter;
|
||||
private ListView mFolderBrowserList;
|
||||
private ListView rootView;
|
||||
private static File currentDir = null;
|
||||
|
||||
// Populates the FolderView with the given currDir's contents.
|
||||
private void Fill(File currDir)
|
||||
{
|
||||
// Change the activity title to reflect the current directory the FolderBrowser is in.
|
||||
// Clear the adapter of previous items.
|
||||
adapter.clear();
|
||||
|
||||
// Set the activity title to the current directory the FolderBrowser is in.
|
||||
getActivity().setTitle(String.format(getString(R.string.current_dir), currDir.getName()));
|
||||
|
||||
|
||||
File[] dirs = currDir.listFiles();
|
||||
List<FolderBrowserItem> dir = new ArrayList<FolderBrowserItem>();
|
||||
List<FolderBrowserItem> fls = new ArrayList<FolderBrowserItem>();
|
||||
@@ -96,9 +97,9 @@ public final class FolderBrowser extends ListFragment
|
||||
if (!currDir.getPath().equalsIgnoreCase("/"))
|
||||
dir.add(0, new FolderBrowserItem("..", getString(R.string.parent_directory), currDir.getParent()));
|
||||
|
||||
adapter = new FolderBrowserAdapter(getActivity(), R.layout.gamelist_folderbrowser_list, dir);
|
||||
mFolderBrowserList = (ListView) rootView.findViewById(R.id.gamelist);
|
||||
mFolderBrowserList.setAdapter(adapter);
|
||||
// Add the items to the adapter and notify the adapter users of its new contents.
|
||||
adapter.addAll(dir);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -122,10 +123,12 @@ public final class FolderBrowser extends ListFragment
|
||||
if(currentDir == null)
|
||||
currentDir = new File(Environment.getExternalStorageDirectory().getPath());
|
||||
|
||||
rootView = (ListView) inflater.inflate(R.layout.gamelist_listview, container, false);
|
||||
ListView rootView = (ListView) inflater.inflate(R.layout.gamelist_listview, container, false);
|
||||
adapter = new FolderBrowserAdapter(getActivity(), R.layout.gamelist_folderbrowser_list_item);
|
||||
rootView.setAdapter(adapter);
|
||||
|
||||
Fill(currentDir);
|
||||
return mFolderBrowserList;
|
||||
return rootView;
|
||||
}
|
||||
|
||||
private void FolderSelected()
|
||||
|
||||
+38
-31
@@ -6,15 +6,12 @@
|
||||
|
||||
package org.dolphinemu.dolphinemu.folderbrowser;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
@@ -27,79 +24,89 @@ import org.dolphinemu.dolphinemu.R;
|
||||
*/
|
||||
public final class FolderBrowserAdapter extends ArrayAdapter<FolderBrowserItem>
|
||||
{
|
||||
// ViewHolder which is used to hold onto
|
||||
// items within a listview. This is done
|
||||
// so that findViewById is not needed to
|
||||
// be excessively called over and over.
|
||||
private static final class ViewHolder
|
||||
{
|
||||
TextView title;
|
||||
TextView subtitle;
|
||||
ImageView icon;
|
||||
}
|
||||
|
||||
private final Context context;
|
||||
private final int id;
|
||||
private final List<FolderBrowserItem> items;
|
||||
private ViewHolder viewHolder;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The current {@link Context}.
|
||||
* @param resourceId The resource ID for a layout file containing a layout to use when instantiating views.
|
||||
* @param objects The objects to represent in the {@link ListView}.
|
||||
*/
|
||||
public FolderBrowserAdapter(Context context, int resourceId, List<FolderBrowserItem> objects)
|
||||
public FolderBrowserAdapter(Context context, int resourceId)
|
||||
{
|
||||
super(context, resourceId, objects);
|
||||
super(context, resourceId);
|
||||
|
||||
this.context = context;
|
||||
this.id = resourceId;
|
||||
this.items = objects;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FolderBrowserItem getItem(int i)
|
||||
{
|
||||
return items.get(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent)
|
||||
{
|
||||
View v = convertView;
|
||||
if (v == null)
|
||||
if (convertView == null)
|
||||
{
|
||||
LayoutInflater vi = LayoutInflater.from(context);
|
||||
v = vi.inflate(id, parent, false);
|
||||
convertView = vi.inflate(id, parent, false);
|
||||
|
||||
// Initialize the ViewHolder and store it.
|
||||
viewHolder = new ViewHolder();
|
||||
viewHolder.title = (TextView) convertView.findViewById(R.id.ListItemTitle);
|
||||
viewHolder.subtitle = (TextView) convertView.findViewById(R.id.ListItemSubTitle);
|
||||
viewHolder.icon = (ImageView) convertView.findViewById(R.id.ListItemIcon);
|
||||
convertView.setTag(viewHolder);
|
||||
}
|
||||
else // Can recover the holder.
|
||||
{
|
||||
viewHolder = (ViewHolder) convertView.getTag();
|
||||
}
|
||||
|
||||
final FolderBrowserItem item = items.get(position);
|
||||
final FolderBrowserItem item = getItem(position);
|
||||
if (item != null)
|
||||
{
|
||||
ImageView icon = (ImageView) v.findViewById(R.id.ListItemIcon);
|
||||
TextView title = (TextView) v.findViewById(R.id.ListItemTitle);
|
||||
TextView subtitle = (TextView) v.findViewById(R.id.ListItemSubTitle);
|
||||
|
||||
if(title != null)
|
||||
if (viewHolder.title != null)
|
||||
{
|
||||
title.setText(item.getName());
|
||||
viewHolder.title.setText(item.getName());
|
||||
}
|
||||
|
||||
if(subtitle != null)
|
||||
if (viewHolder.subtitle != null)
|
||||
{
|
||||
// Remove the subtitle for all folders, except for the parent directory folder.
|
||||
if (item.isDirectory() && !item.getSubtitle().equals(context.getString(R.string.parent_directory)))
|
||||
{
|
||||
subtitle.setVisibility(View.GONE);
|
||||
viewHolder.subtitle.setVisibility(View.GONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
subtitle.setText(item.getSubtitle());
|
||||
viewHolder.subtitle.setVisibility(View.VISIBLE);
|
||||
viewHolder.subtitle.setText(item.getSubtitle());
|
||||
}
|
||||
}
|
||||
|
||||
if (icon != null)
|
||||
if (viewHolder.icon != null)
|
||||
{
|
||||
if (item.isDirectory())
|
||||
{
|
||||
icon.setImageResource(R.drawable.ic_menu_folder);
|
||||
viewHolder.icon.setImageResource(R.drawable.ic_menu_folder);
|
||||
}
|
||||
else
|
||||
{
|
||||
icon.setImageResource(R.drawable.ic_menu_file);
|
||||
viewHolder.icon.setImageResource(R.drawable.ic_menu_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
return v;
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,11 @@ package org.dolphinemu.dolphinemu.gamelist;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.ActionBarDrawerToggle;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
@@ -41,7 +42,6 @@ public final class GameListActivity extends Activity
|
||||
implements GameListFragment.OnGameListZeroListener
|
||||
{
|
||||
private int mCurFragmentNum = 0;
|
||||
private Fragment mCurFragment;
|
||||
|
||||
private ActionBarDrawerToggle mDrawerToggle;
|
||||
private DrawerLayout mDrawerLayout;
|
||||
@@ -102,10 +102,36 @@ public final class GameListActivity extends Activity
|
||||
};
|
||||
mDrawerLayout.setDrawerListener(mDrawerToggle);
|
||||
|
||||
// Display the game list fragment.
|
||||
mCurFragment = new GameListFragment();
|
||||
FragmentManager fragmentManager = getFragmentManager();
|
||||
fragmentManager.beginTransaction().replace(R.id.content_frame, mCurFragment).commit();
|
||||
// Display the game list fragment on activity creation,
|
||||
// but only if no previous states have been saved.
|
||||
if (savedInstanceState == null)
|
||||
{
|
||||
final GameListFragment gameList = new GameListFragment();
|
||||
FragmentTransaction ft = getFragmentManager().beginTransaction();
|
||||
ft.replace(R.id.content_frame, gameList);
|
||||
ft.commit();
|
||||
}
|
||||
|
||||
|
||||
// Create an alert telling them that their phone sucks
|
||||
if (Build.CPU_ABI.contains("arm") && !NativeLibrary.SupportsNEON())
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.device_compat_warning);
|
||||
builder.setMessage(R.string.device_compat_warning_msg);
|
||||
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Do Nothing. Just create the Yes button
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
finish();
|
||||
}
|
||||
});
|
||||
builder.show();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,9 +155,10 @@ public final class GameListActivity extends Activity
|
||||
setTitle(R.string.app_name);
|
||||
|
||||
mCurFragmentNum = 0;
|
||||
mCurFragment = new GameListFragment();
|
||||
FragmentManager fragmentManager = getFragmentManager();
|
||||
fragmentManager.beginTransaction().replace(R.id.content_frame, mCurFragment).commit();
|
||||
final GameListFragment gameList = new GameListFragment();
|
||||
FragmentTransaction ft = getFragmentManager().beginTransaction();
|
||||
ft.replace(R.id.content_frame, gameList);
|
||||
ft.commit();
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
break;
|
||||
@@ -139,9 +166,11 @@ public final class GameListActivity extends Activity
|
||||
case 1: // Folder Browser
|
||||
{
|
||||
mCurFragmentNum = 1;
|
||||
mCurFragment = new FolderBrowser();
|
||||
FragmentManager fragmentManager = getFragmentManager();
|
||||
fragmentManager.beginTransaction().replace(R.id.content_frame, mCurFragment).commit();
|
||||
final FolderBrowser folderBrowser = new FolderBrowser();
|
||||
FragmentTransaction ft = getFragmentManager().beginTransaction();
|
||||
ft.replace(R.id.content_frame, folderBrowser);
|
||||
ft.addToBackStack(null);
|
||||
ft.commit();
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
break;
|
||||
@@ -156,9 +185,11 @@ public final class GameListActivity extends Activity
|
||||
case 3: // About
|
||||
{
|
||||
mCurFragmentNum = 3;
|
||||
mCurFragment = new AboutFragment();
|
||||
FragmentManager fragmentManager = getFragmentManager();
|
||||
fragmentManager.beginTransaction().replace(R.id.content_frame, mCurFragment).commit();
|
||||
final AboutFragment aboutFragment = new AboutFragment();
|
||||
FragmentTransaction ft = getFragmentManager().beginTransaction();
|
||||
ft.replace(R.id.content_frame, aboutFragment);
|
||||
ft.addToBackStack(null);
|
||||
ft.commit();
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
break;
|
||||
@@ -245,7 +276,7 @@ public final class GameListActivity extends Activity
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "General", "GCMPathes", "0");
|
||||
|
||||
// Now finally, clear the game list.
|
||||
((GameListFragment) mCurFragment).clearGameList();
|
||||
((GameListFragment) getFragmentManager().findFragmentById(R.id.content_frame)).clearGameList();
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
|
||||
@@ -260,7 +291,23 @@ public final class GameListActivity extends Activity
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState)
|
||||
{
|
||||
super.onSaveInstanceState(outState);
|
||||
|
||||
outState.putInt("currentFragmentNum", mCurFragmentNum);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Bundle savedInstanceState)
|
||||
{
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
|
||||
mCurFragmentNum = savedInstanceState.getInt("currentFragmentNum");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed()
|
||||
{
|
||||
|
||||
@@ -12,11 +12,8 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
|
||||
/**
|
||||
@@ -28,46 +25,36 @@ public final class GameListAdapter extends ArrayAdapter<GameListItem>
|
||||
{
|
||||
private final Context context;
|
||||
private final int id;
|
||||
private final List<GameListItem>items;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The current {@link Context}.
|
||||
* @param resourceId The resource ID for a layout file containing a layout to use when instantiating views.
|
||||
* @param objects The objects to represent in the {@link ListView}.
|
||||
*/
|
||||
public GameListAdapter(Context context, int resourceId, List<GameListItem> objects)
|
||||
public GameListAdapter(Context context, int resourceId)
|
||||
{
|
||||
super(context, resourceId, objects);
|
||||
super(context, resourceId);
|
||||
|
||||
this.context = context;
|
||||
this.id = resourceId;
|
||||
this.items = objects;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameListItem getItem(int i)
|
||||
{
|
||||
return items.get(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent)
|
||||
{
|
||||
View v = convertView;
|
||||
if (v == null)
|
||||
if (convertView == null)
|
||||
{
|
||||
LayoutInflater vi = LayoutInflater.from(context);
|
||||
v = vi.inflate(id, parent, false);
|
||||
convertView = vi.inflate(id, parent, false);
|
||||
}
|
||||
|
||||
final GameListItem item = items.get(position);
|
||||
final GameListItem item = getItem(position);
|
||||
if (item != null)
|
||||
{
|
||||
TextView title = (TextView) v.findViewById(R.id.ListItemTitle);
|
||||
TextView subtitle = (TextView) v.findViewById(R.id.ListItemSubTitle);
|
||||
ImageView icon = (ImageView) v.findViewById(R.id.ListItemIcon);
|
||||
TextView title = (TextView) convertView.findViewById(R.id.ListItemTitle);
|
||||
TextView subtitle = (TextView) convertView.findViewById(R.id.ListItemSubTitle);
|
||||
ImageView icon = (ImageView) convertView.findViewById(R.id.ListItemIcon);
|
||||
|
||||
if (title != null)
|
||||
title.setText(item.getName());
|
||||
@@ -83,7 +70,7 @@ public final class GameListAdapter extends ArrayAdapter<GameListItem>
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ import org.dolphinemu.dolphinemu.emulation.EmulationActivity;
|
||||
public final class GameListFragment extends ListFragment
|
||||
{
|
||||
private GameListAdapter mGameAdapter;
|
||||
private static GameListActivity mMe;
|
||||
private OnGameListZeroListener mCallback;
|
||||
|
||||
/**
|
||||
@@ -84,7 +83,7 @@ public final class GameListFragment extends ListFragment
|
||||
if (!entry.isHidden() && !entry.isDirectory())
|
||||
{
|
||||
if (exts.contains(entryName.toLowerCase().substring(entryName.lastIndexOf('.'))))
|
||||
fls.add(new GameListItem(mMe, entryName, String.format(getString(R.string.file_size), entry.length()), entry.getAbsolutePath()));
|
||||
fls.add(new GameListItem(getActivity(), entryName, String.format(getString(R.string.file_size), entry.length()), entry.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,8 +93,9 @@ public final class GameListFragment extends ListFragment
|
||||
}
|
||||
Collections.sort(fls);
|
||||
|
||||
mGameAdapter = new GameListAdapter(mMe, R.layout.gamelist_folderbrowser_list, fls);
|
||||
setListAdapter(mGameAdapter);
|
||||
// Add all the items to the adapter
|
||||
mGameAdapter.addAll(fls);
|
||||
mGameAdapter.notifyDataSetChanged();
|
||||
|
||||
if (fls.isEmpty())
|
||||
{
|
||||
@@ -106,12 +106,13 @@ public final class GameListFragment extends ListFragment
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
View rootView = inflater.inflate(R.layout.gamelist_listview, container, false);
|
||||
ListView mMainList = (ListView) rootView.findViewById(R.id.gamelist);
|
||||
ListView rootView = (ListView) inflater.inflate(R.layout.gamelist_listview, container, false);
|
||||
mGameAdapter = new GameListAdapter(getActivity(), R.layout.gamelist_folderbrowser_list_item);
|
||||
rootView.setAdapter(mGameAdapter);
|
||||
|
||||
Fill();
|
||||
|
||||
return mMainList;
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -120,12 +121,12 @@ public final class GameListFragment extends ListFragment
|
||||
GameListItem item = mGameAdapter.getItem(position);
|
||||
|
||||
// Show a toast indicating which game was clicked.
|
||||
Toast.makeText(mMe, String.format(getString(R.string.file_clicked), item.getPath()), Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(getActivity(), String.format(getString(R.string.file_clicked), item.getPath()), Toast.LENGTH_SHORT).show();
|
||||
|
||||
// Start the emulation activity and send the path of the clicked ROM to it.
|
||||
Intent intent = new Intent(mMe, EmulationActivity.class);
|
||||
Intent intent = new Intent(getActivity(), EmulationActivity.class);
|
||||
intent.putExtra("SelectedGame", item.getPath());
|
||||
mMe.startActivity(intent);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -138,7 +139,6 @@ public final class GameListFragment extends ListFragment
|
||||
try
|
||||
{
|
||||
mCallback = (OnGameListZeroListener) activity;
|
||||
mMe = (GameListActivity) activity;
|
||||
}
|
||||
catch (ClassCastException e)
|
||||
{
|
||||
|
||||
+3
-11
@@ -27,6 +27,7 @@ public final class VideoSettingsFragment extends PreferenceFragment
|
||||
public static String m_GLVendor;
|
||||
public static String m_GLRenderer;
|
||||
public static String m_GLExtensions;
|
||||
public static float m_QualcommVersion;
|
||||
|
||||
/**
|
||||
* Class which provides a means to retrieve various
|
||||
@@ -163,7 +164,6 @@ public final class VideoSettingsFragment extends PreferenceFragment
|
||||
{
|
||||
int mVStart = m_GLVersion.indexOf("V@") + 2;
|
||||
int mVEnd = 0;
|
||||
float mVersion;
|
||||
|
||||
for (int a = mVStart; a < m_GLVersion.length(); ++a)
|
||||
{
|
||||
@@ -174,20 +174,12 @@ public final class VideoSettingsFragment extends PreferenceFragment
|
||||
}
|
||||
}
|
||||
|
||||
mVersion = Float.parseFloat(m_GLVersion.substring(mVStart, mVEnd));
|
||||
m_QualcommVersion = Float.parseFloat(m_GLVersion.substring(mVStart, mVEnd));
|
||||
|
||||
if (mVersion >= 14.0f)
|
||||
if (m_QualcommVersion >= 14.0f)
|
||||
mSupportsGLES3 = true;
|
||||
}
|
||||
}
|
||||
if (!mSupportsGLES3 &&
|
||||
m_GLVendor != null && m_GLVendor.equals("NVIDIA Corporation") &&
|
||||
m_GLRenderer != null && m_GLRenderer.equals("NVIDIA Tegra") &&
|
||||
m_GLExtensions != null && m_GLExtensions.contains("GL_OES_depth24"))
|
||||
{
|
||||
// Is a Tegra 4 since it supports 24bit depth
|
||||
mSupportsGLES3 = true;
|
||||
}
|
||||
return mSupportsGLES3;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,23 +54,22 @@ public final class SideMenuAdapter extends ArrayAdapter<SideMenuItem>
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent)
|
||||
{
|
||||
View v = convertView;
|
||||
if (v == null)
|
||||
if (convertView == null)
|
||||
{
|
||||
LayoutInflater vi = LayoutInflater.from(context);
|
||||
v = vi.inflate(id, null);
|
||||
convertView = vi.inflate(id, null);
|
||||
}
|
||||
|
||||
final SideMenuItem item = items.get(position);
|
||||
if (item != null)
|
||||
{
|
||||
TextView title = (TextView) v.findViewById(R.id.SideMenuTitle);
|
||||
TextView title = (TextView) convertView.findViewById(R.id.SideMenuTitle);
|
||||
|
||||
if (title != null)
|
||||
title.setText(item.getName());
|
||||
}
|
||||
|
||||
return v;
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,12 @@ struct CPUInfo
|
||||
bool bAVX;
|
||||
bool bFMA;
|
||||
bool bAES;
|
||||
// FXSAVE/FXRSTOR
|
||||
bool bFXSR;
|
||||
// This flag indicates that the hardware supports some mode
|
||||
// in which denormal inputs _and_ outputs are automatically set to (signed) zero.
|
||||
// TODO: ARM
|
||||
bool bFlushToZero;
|
||||
bool bLAHFSAHF64;
|
||||
bool bLongMode;
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace FPURoundMode
|
||||
|
||||
void SetPrecisionMode(u32 mode);
|
||||
|
||||
void SetSIMDMode(u32 mode);
|
||||
void SetSIMDMode(u32 roundingMode, u32 nonIEEEMode);
|
||||
|
||||
/*
|
||||
* There are two different flavors of float to int conversion:
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace FPURoundMode
|
||||
void SetPrecisionMode(u32 mode)
|
||||
{
|
||||
}
|
||||
void SetSIMDMode(u32 mode)
|
||||
void SetSIMDMode(u32 mode, u32 nonIEEEMode)
|
||||
{
|
||||
}
|
||||
void SaveSIMDState()
|
||||
|
||||
@@ -64,10 +64,10 @@ inline float FlushToZero(float f)
|
||||
return x.f;
|
||||
}
|
||||
|
||||
inline double FlushToZeroAsFloat(double d)
|
||||
inline double FlushToZero(double d)
|
||||
{
|
||||
IntDouble x; x.d = d;
|
||||
if ((x.i & DOUBLE_EXP) < 0x3800000000000000ULL)
|
||||
if ((x.i & DOUBLE_EXP) == 0)
|
||||
x.i &= DOUBLE_SIGN; // turn into signed zero
|
||||
return x.d;
|
||||
}
|
||||
|
||||
@@ -162,6 +162,34 @@ void CPUInfo::Detect()
|
||||
if ((cpu_id[2] >> 20) & 1) bSSE4_2 = true;
|
||||
if ((cpu_id[2] >> 25) & 1) bAES = true;
|
||||
|
||||
// To check DAZ support, we first need to check FXSAVE support.
|
||||
if ((cpu_id[3] >> 24) & 1)
|
||||
{
|
||||
// We can use FXSAVE.
|
||||
bFXSR = true;
|
||||
|
||||
GC_ALIGNED16(u8 fx_state[512]);
|
||||
memset(fx_state, 0, sizeof(fx_state));
|
||||
#ifdef _WIN32
|
||||
#ifdef _M_IX86
|
||||
_fxsave(fx_state);
|
||||
#elif defined (_M_X64)
|
||||
_fxsave64(fx_state);
|
||||
#endif
|
||||
#else
|
||||
__asm__("fxsave %0" : "=m" (fx_state));
|
||||
#endif
|
||||
|
||||
// lowest byte of MXCSR_MASK
|
||||
if ((fx_state[0x1C] >> 6) & 1)
|
||||
{
|
||||
// On x86, the FTZ field (supported since SSE1) only flushes denormal _outputs_ to zero,
|
||||
// now that we checked DAZ support (flushing denormal _inputs_ to zero),
|
||||
// we can set our generic flag.
|
||||
bFlushToZero = true;
|
||||
}
|
||||
}
|
||||
|
||||
// AVX support requires 3 separate checks:
|
||||
// - Is the AVX bit set in CPUID?
|
||||
// - Is the XSAVE bit set in CPUID?
|
||||
@@ -222,7 +250,12 @@ std::string CPUInfo::Summarize()
|
||||
{
|
||||
std::string sum(cpu_string);
|
||||
if (bSSE) sum += ", SSE";
|
||||
if (bSSE2) sum += ", SSE2";
|
||||
if (bSSE2)
|
||||
{
|
||||
sum += ", SSE2";
|
||||
if (!bFlushToZero)
|
||||
sum += " (but not DAZ!)";
|
||||
}
|
||||
if (bSSE3) sum += ", SSE3";
|
||||
if (bSSSE3) sum += ", SSSE3";
|
||||
if (bSSE4_1) sum += ", SSE4.1";
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "Common.h"
|
||||
#include "FPURoundMode.h"
|
||||
#include "CPUDetect.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
static const unsigned short FPU_ROUND_NEAR = 0 << 10;
|
||||
@@ -14,8 +15,11 @@ static const unsigned short FPU_ROUND_MASK = 3 << 10;
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
const u32 MASKS = 0x1F80; // mask away the interrupts.
|
||||
// OR-mask for disabling FPU exceptions (bits 7-12 in the MXCSR register)
|
||||
const u32 EXCEPTION_MASK = 0x1F80;
|
||||
// Denormals-Are-Zero (non-IEEE mode: denormal inputs are set to +/- 0)
|
||||
const u32 DAZ = 0x40;
|
||||
// Flush-To-Zero (non-IEEE mode: denormal outputs are set to +/- 0)
|
||||
const u32 FTZ = 0x8000;
|
||||
|
||||
namespace FPURoundMode
|
||||
@@ -79,16 +83,28 @@ namespace FPURoundMode
|
||||
//but still - set any useful sse options here
|
||||
#endif
|
||||
}
|
||||
void SetSIMDMode(u32 mode)
|
||||
|
||||
void SetSIMDMode(u32 roundingMode, u32 nonIEEEMode)
|
||||
{
|
||||
static const u32 ssetable[4] =
|
||||
// lookup table for FPSCR.RN-to-MXCSR.RC translation
|
||||
static const u32 roundingModeLUT[4] =
|
||||
{
|
||||
(0 << 13) | MASKS,
|
||||
(3 << 13) | MASKS,
|
||||
(2 << 13) | MASKS,
|
||||
(1 << 13) | MASKS,
|
||||
(0 << 13) | EXCEPTION_MASK, // nearest
|
||||
(3 << 13) | EXCEPTION_MASK, // -inf
|
||||
(2 << 13) | EXCEPTION_MASK, // +inf
|
||||
(1 << 13) | EXCEPTION_MASK, // zero
|
||||
};
|
||||
u32 csr = ssetable[mode];
|
||||
u32 csr = roundingModeLUT[roundingMode];
|
||||
|
||||
static const u32 denormalLUT[2] =
|
||||
{
|
||||
FTZ, // flush-to-zero only
|
||||
FTZ | DAZ, // flush-to-zero and denormals-are-zero (may not be supported)
|
||||
};
|
||||
if (nonIEEEMode)
|
||||
{
|
||||
csr |= denormalLUT[cpu_info.bFlushToZero];
|
||||
}
|
||||
_mm_setcsr(csr);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
#include "PowerPCDisasm.h"
|
||||
#include "Console.h"
|
||||
|
||||
#define CASE1(x) if (memcmp(cmd, x, 2*sizeof(TCHAR))==0)
|
||||
#define CASE(x) else if (memcmp(cmd, x, 4*sizeof(TCHAR))==0)
|
||||
#define CASE1(x) if (!strcmp(cmd, (x)))
|
||||
#define CASE(x) else if (!strcmp(cmd, (x)))
|
||||
|
||||
void Console_Submit(const char *cmd)
|
||||
{
|
||||
@@ -27,7 +27,7 @@ void Console_Submit(const char *cmd)
|
||||
Core::StartTrace(false);
|
||||
INFO_LOG(CONSOLE, "Read tracing started.");
|
||||
}
|
||||
CASE1("w")
|
||||
CASE("w")
|
||||
{
|
||||
Core::StartTrace(true);
|
||||
INFO_LOG(CONSOLE, "Write tracing started.");
|
||||
@@ -141,3 +141,6 @@ void Console_Submit(const char *cmd)
|
||||
ERROR_LOG(CONSOLE, "Invalid command");
|
||||
}
|
||||
}
|
||||
|
||||
#undef CASE1
|
||||
#undef CASE
|
||||
|
||||
@@ -113,13 +113,17 @@ static bool VerifyRoms(const char *irom_filename, const char *coef_filename)
|
||||
}
|
||||
|
||||
if (rom_idx == 1)
|
||||
PanicAlertT("You are using an old free DSP ROM made by the Dolphin Team.\n"
|
||||
"Only games using the Zelda UCode will work correctly.\n");
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
if (rom_idx == 2)
|
||||
PanicAlertT("You are using a free DSP ROM made by the Dolphin Team.\n"
|
||||
"All Wii games will work correctly, and most GC games should "
|
||||
"also work fine, but the GBA/IPL/CARD UCodes will not work.\n");
|
||||
{
|
||||
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);
|
||||
DSPHost_OSD_AddMessage("also work fine, but the GBA/IPL/CARD UCodes will not work.\n", 8000);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
u8 DSPHost_ReadHostMemory(u32 addr);
|
||||
void DSPHost_WriteHostMemory(u8 value, u32 addr);
|
||||
void DSPHost_OSD_AddMessage(const std::string& str, u32 ms);
|
||||
bool DSPHost_OnThread();
|
||||
bool DSPHost_Wii();
|
||||
void DSPHost_InterruptRequest();
|
||||
|
||||
@@ -86,7 +86,7 @@ bool FifoDataFile::Save(const char *filename)
|
||||
header.xfRegsSize = XF_REGS_SIZE;
|
||||
|
||||
header.frameListOffset = frameListOffset;
|
||||
header.frameCount = m_Frames.size();
|
||||
header.frameCount = (u32)m_Frames.size();
|
||||
|
||||
header.flags = m_Flags;
|
||||
|
||||
@@ -111,7 +111,7 @@ bool FifoDataFile::Save(const char *filename)
|
||||
dstFrame.fifoStart = srcFrame.fifoStart;
|
||||
dstFrame.fifoEnd = srcFrame.fifoEnd;
|
||||
dstFrame.memoryUpdatesOffset = memoryUpdatesOffset;
|
||||
dstFrame.numMemoryUpdates = srcFrame.memoryUpdates.size();
|
||||
dstFrame.numMemoryUpdates = (u32)srcFrame.memoryUpdates.size();
|
||||
|
||||
// Write frame info
|
||||
u64 frameOffset = frameListOffset + (i * sizeof(FileFrameInfo));
|
||||
|
||||
@@ -234,7 +234,7 @@ u32 FifoPlaybackAnalyzer::DecodeCommand(u8 *data)
|
||||
break;
|
||||
}
|
||||
|
||||
return data - dataStart;
|
||||
return (u32)(data - dataStart);
|
||||
}
|
||||
|
||||
void FifoPlaybackAnalyzer::StoreEfbCopyRegion()
|
||||
|
||||
@@ -105,7 +105,9 @@ bool FifoPlayer::Play()
|
||||
u32 FifoPlayer::GetFrameObjectCount()
|
||||
{
|
||||
if (m_CurrentFrame < m_FrameInfo.size())
|
||||
return m_FrameInfo[m_CurrentFrame].objectStarts.size();
|
||||
{
|
||||
return (u32)(m_FrameInfo[m_CurrentFrame].objectStarts.size());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -172,7 +174,7 @@ void FifoPlayer::WriteFrame(const FifoFrameInfo &frame, const AnalyzedFrameInfo
|
||||
m_FrameFifoSize = frame.fifoDataSize;
|
||||
|
||||
// Determine start and end objects
|
||||
u32 numObjects = info.objectStarts.size();
|
||||
u32 numObjects = (u32)(info.objectStarts.size());
|
||||
u32 drawStart = std::min(numObjects, m_ObjectRangeStart);
|
||||
u32 drawEnd = std::min(numObjects - 1, m_ObjectRangeEnd);
|
||||
|
||||
@@ -181,7 +183,9 @@ void FifoPlayer::WriteFrame(const FifoFrameInfo &frame, const AnalyzedFrameInfo
|
||||
|
||||
// Skip memory updates during frame if true
|
||||
if (m_EarlyMemoryUpdates)
|
||||
memoryUpdate = frame.memoryUpdates.size();
|
||||
{
|
||||
memoryUpdate = (u32)(frame.memoryUpdates.size());
|
||||
}
|
||||
|
||||
if (numObjects > 0)
|
||||
{
|
||||
|
||||
@@ -83,9 +83,9 @@ void FifoRecorder::WriteGPCommand(u8 *data, u32 size)
|
||||
if (m_FrameEnded && m_FifoData.size() > 0)
|
||||
{
|
||||
size_t dataSize = m_FifoData.size();
|
||||
m_CurrentFrame.fifoDataSize = dataSize;
|
||||
m_CurrentFrame.fifoDataSize = (u32)dataSize;
|
||||
m_CurrentFrame.fifoData = new u8[dataSize];
|
||||
memcpy(m_CurrentFrame.fifoData, &m_FifoData[0], dataSize);
|
||||
memcpy(m_CurrentFrame.fifoData, m_FifoData.data(), dataSize);
|
||||
|
||||
sMutex.lock();
|
||||
|
||||
@@ -129,7 +129,7 @@ void FifoRecorder::WriteMemory(u32 address, u32 size, MemoryUpdate::Type type)
|
||||
// Record memory update
|
||||
MemoryUpdate memUpdate;
|
||||
memUpdate.address = address;
|
||||
memUpdate.fifoPosition = m_FifoData.size();
|
||||
memUpdate.fifoPosition = (u32)(m_FifoData.size());
|
||||
memUpdate.size = size;
|
||||
memUpdate.type = type;
|
||||
memUpdate.data = new u8[size];
|
||||
|
||||
@@ -469,36 +469,42 @@ void ProcessVoice(PB_TYPE& pb, const AXBuffers& buffers, u16 count, AXMixControl
|
||||
// Mix LRS, AUXA and AUXB depending on mixer_control
|
||||
// TODO: Handle DPL2 on AUXB.
|
||||
|
||||
if (mctrl & MIX_L)
|
||||
MixAdd(buffers.left, samples, count, &pb.mixer.left, &pb.dpop.left, mctrl & MIX_L_RAMP);
|
||||
if (mctrl & MIX_R)
|
||||
MixAdd(buffers.right, samples, count, &pb.mixer.right, &pb.dpop.right, mctrl & MIX_R_RAMP);
|
||||
if (mctrl & MIX_S)
|
||||
MixAdd(buffers.surround, samples, count, &pb.mixer.surround, &pb.dpop.surround, mctrl & MIX_S_RAMP);
|
||||
#define MIX_ON(C) (0 != (mctrl & MIX_##C))
|
||||
#define RAMP_ON(C) (0 != (mctrl & MIX_##C##_RAMP))
|
||||
|
||||
if (mctrl & MIX_AUXA_L)
|
||||
MixAdd(buffers.auxA_left, samples, count, &pb.mixer.auxA_left, &pb.dpop.auxA_left, mctrl & MIX_AUXA_L_RAMP);
|
||||
if (mctrl & MIX_AUXA_R)
|
||||
MixAdd(buffers.auxA_right, samples, count, &pb.mixer.auxA_right, &pb.dpop.auxA_right, mctrl & MIX_AUXA_R_RAMP);
|
||||
if (mctrl & MIX_AUXA_S)
|
||||
MixAdd(buffers.auxA_surround, samples, count, &pb.mixer.auxA_surround, &pb.dpop.auxA_surround, mctrl & MIX_AUXA_S_RAMP);
|
||||
if (MIX_ON(L))
|
||||
MixAdd(buffers.left, samples, count, &pb.mixer.left, &pb.dpop.left, RAMP_ON(L));
|
||||
if (MIX_ON(R))
|
||||
MixAdd(buffers.right, samples, count, &pb.mixer.right, &pb.dpop.right, RAMP_ON(R));
|
||||
if (MIX_ON(S))
|
||||
MixAdd(buffers.surround, samples, count, &pb.mixer.surround, &pb.dpop.surround, RAMP_ON(S));
|
||||
|
||||
if (mctrl & MIX_AUXB_L)
|
||||
MixAdd(buffers.auxB_left, samples, count, &pb.mixer.auxB_left, &pb.dpop.auxB_left, mctrl & MIX_AUXB_L_RAMP);
|
||||
if (mctrl & MIX_AUXB_R)
|
||||
MixAdd(buffers.auxB_right, samples, count, &pb.mixer.auxB_right, &pb.dpop.auxB_right, mctrl & MIX_AUXB_R_RAMP);
|
||||
if (mctrl & MIX_AUXB_S)
|
||||
MixAdd(buffers.auxB_surround, samples, count, &pb.mixer.auxB_surround, &pb.dpop.auxB_surround, mctrl & MIX_AUXB_S_RAMP);
|
||||
if (MIX_ON(AUXA_L))
|
||||
MixAdd(buffers.auxA_left, samples, count, &pb.mixer.auxA_left, &pb.dpop.auxA_left, RAMP_ON(AUXA_L));
|
||||
if (MIX_ON(AUXA_R))
|
||||
MixAdd(buffers.auxA_right, samples, count, &pb.mixer.auxA_right, &pb.dpop.auxA_right, RAMP_ON(AUXA_R));
|
||||
if (MIX_ON(AUXA_S))
|
||||
MixAdd(buffers.auxA_surround, samples, count, &pb.mixer.auxA_surround, &pb.dpop.auxA_surround, RAMP_ON(AUXA_S));
|
||||
|
||||
if (MIX_ON(AUXB_L))
|
||||
MixAdd(buffers.auxB_left, samples, count, &pb.mixer.auxB_left, &pb.dpop.auxB_left, RAMP_ON(AUXB_L));
|
||||
if (MIX_ON(AUXB_R))
|
||||
MixAdd(buffers.auxB_right, samples, count, &pb.mixer.auxB_right, &pb.dpop.auxB_right, RAMP_ON(AUXB_R));
|
||||
if (MIX_ON(AUXB_S))
|
||||
MixAdd(buffers.auxB_surround, samples, count, &pb.mixer.auxB_surround, &pb.dpop.auxB_surround, RAMP_ON(AUXB_S));
|
||||
|
||||
#ifdef AX_WII
|
||||
if (mctrl & MIX_AUXC_L)
|
||||
MixAdd(buffers.auxC_left, samples, count, &pb.mixer.auxC_left, &pb.dpop.auxC_left, mctrl & MIX_AUXC_L_RAMP);
|
||||
if (mctrl & MIX_AUXC_R)
|
||||
MixAdd(buffers.auxC_right, samples, count, &pb.mixer.auxC_right, &pb.dpop.auxC_right, mctrl & MIX_AUXC_R_RAMP);
|
||||
if (mctrl & MIX_AUXC_S)
|
||||
MixAdd(buffers.auxC_surround, samples, count, &pb.mixer.auxC_surround, &pb.dpop.auxC_surround, mctrl & MIX_AUXC_S_RAMP);
|
||||
if (MIX_ON(AUXC_L))
|
||||
MixAdd(buffers.auxC_left, samples, count, &pb.mixer.auxC_left, &pb.dpop.auxC_left, RAMP_ON(AUXC_L));
|
||||
if (MIX_ON(AUXC_R))
|
||||
MixAdd(buffers.auxC_right, samples, count, &pb.mixer.auxC_right, &pb.dpop.auxC_right, RAMP_ON(AUXC_R));
|
||||
if (MIX_ON(AUXC_S))
|
||||
MixAdd(buffers.auxC_surround, samples, count, &pb.mixer.auxC_surround, &pb.dpop.auxC_surround, RAMP_ON(AUXC_S));
|
||||
#endif
|
||||
|
||||
#undef MIX_ON
|
||||
#undef RAMP_ON
|
||||
|
||||
// Optionally, phase shift left or right channel to simulate 3D sound.
|
||||
if (pb.initial_time_delay.on)
|
||||
{
|
||||
@@ -524,8 +530,8 @@ void ProcessVoice(PB_TYPE& pb, const AXBuffers& buffers, u16 count, AXMixControl
|
||||
pb.remote_src.cur_addr_frac = curr_pos & 0xFFFF;
|
||||
|
||||
// Mix to main[0-3] and aux[0-3]
|
||||
#define WMCHAN_MIX_ON(n) ((pb.remote_mixer_control >> (2 * n)) & 3)
|
||||
#define WMCHAN_MIX_RAMP(n) ((pb.remote_mixer_control >> (2 * n)) & 2)
|
||||
#define WMCHAN_MIX_ON(n) (0 != ((pb.remote_mixer_control >> (2 * n)) & 3))
|
||||
#define WMCHAN_MIX_RAMP(n) (0 != ((pb.remote_mixer_control >> (2 * n)) & 2))
|
||||
|
||||
if (WMCHAN_MIX_ON(0))
|
||||
MixAdd(buffers.wm_main0, wm_samples, wm_count, &pb.remote_mixer.main0, &pb.remote_dpop.main0, WMCHAN_MIX_RAMP(0));
|
||||
@@ -544,6 +550,8 @@ void ProcessVoice(PB_TYPE& pb, const AXBuffers& buffers, u16 count, AXMixControl
|
||||
if (WMCHAN_MIX_ON(7))
|
||||
MixAdd(buffers.wm_aux3, wm_samples, wm_count, &pb.remote_mixer.aux3, &pb.remote_dpop.aux3, WMCHAN_MIX_RAMP(7));
|
||||
}
|
||||
#undef WMCHAN_MIX_RAMP
|
||||
#undef WMCHAN_MIX_ON
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "../../ConfigManager.h"
|
||||
#include "../../PowerPC/PowerPC.h"
|
||||
#include "Host.h"
|
||||
#include "OnScreenDisplay.h"
|
||||
|
||||
// The user of the DSPCore library must supply a few functions so that the
|
||||
// emulation core can access the environment it runs in. If the emulation
|
||||
@@ -29,6 +30,11 @@ void DSPHost_WriteHostMemory(u8 value, u32 addr)
|
||||
DSP::WriteARAM(value, addr);
|
||||
}
|
||||
|
||||
void DSPHost_OSD_AddMessage(const std::string& str, u32 ms)
|
||||
{
|
||||
OSD::AddMessage(str, ms);
|
||||
}
|
||||
|
||||
bool DSPHost_OnThread()
|
||||
{
|
||||
const SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;
|
||||
|
||||
@@ -325,7 +325,7 @@ void ChangeDisc(const char* _newFileName)
|
||||
{
|
||||
Movie::g_bDiscChange = true;
|
||||
std::string fileName = _newFileName;
|
||||
int sizeofpath = fileName.find_last_of("/\\") + 1;
|
||||
auto sizeofpath = fileName.find_last_of("/\\") + 1;
|
||||
if (fileName.substr(sizeofpath).length() > 40)
|
||||
{
|
||||
PanicAlert("Saving iso filename to .dtm failed; max file name length is 40 characters.");
|
||||
|
||||
@@ -191,7 +191,7 @@ void CEXIMemoryCard::CmdDone()
|
||||
void CEXIMemoryCard::CmdDoneLater(u64 cycles)
|
||||
{
|
||||
CoreTiming::RemoveEvent(et_cmd_done);
|
||||
CoreTiming::ScheduleEvent(cycles, et_cmd_done, (u64)card_index);
|
||||
CoreTiming::ScheduleEvent((int)cycles, et_cmd_done, (u64)card_index);
|
||||
}
|
||||
|
||||
void CEXIMemoryCard::SetCS(int cs)
|
||||
|
||||
@@ -40,19 +40,19 @@ GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis)
|
||||
PanicAlertT("File has the extension \"%s\"\nvalid extensions are (.raw/.gcp)", fileType.c_str());
|
||||
return;
|
||||
}
|
||||
u32 size = mcdFile.GetSize();
|
||||
auto size = mcdFile.GetSize();
|
||||
if (size < MC_FST_BLOCKS*BLOCK_SIZE)
|
||||
{
|
||||
PanicAlertT("%s failed to load as a memorycard \nfile is not large enough to be a valid memory card file (0x%x bytes)", filename, size);
|
||||
PanicAlertT("%s failed to load as a memorycard \nfile is not large enough to be a valid memory card file (0x%x bytes)", filename, (unsigned) size);
|
||||
return;
|
||||
}
|
||||
if (size % BLOCK_SIZE)
|
||||
{
|
||||
PanicAlertT("%s failed to load as a memorycard \n Card file size is invalid (0x%x bytes)", filename, size);
|
||||
PanicAlertT("%s failed to load as a memorycard \n Card file size is invalid (0x%x bytes)", filename, (unsigned) size);
|
||||
return;
|
||||
}
|
||||
|
||||
m_sizeMb = (size/BLOCK_SIZE) / MBIT_TO_BLOCKS;
|
||||
m_sizeMb = (u16)((size/BLOCK_SIZE) / MBIT_TO_BLOCKS);
|
||||
switch (m_sizeMb)
|
||||
{
|
||||
case MemCard59Mb:
|
||||
@@ -63,7 +63,7 @@ GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis)
|
||||
case MemCard2043Mb:
|
||||
break;
|
||||
default:
|
||||
PanicAlertT("%s failed to load as a memorycard \n Card size is invalid (0x%x bytes)", filename, size);
|
||||
PanicAlertT("%s failed to load as a memorycard \n Card size is invalid (0x%x bytes)", filename, (unsigned) size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,5 +209,5 @@ void GCPad::LoadDefaults(const ControllerInterface& ciface)
|
||||
|
||||
bool GCPad::GetMicButton() const
|
||||
{
|
||||
return m_buttons->controls.back()->control_ref->State();
|
||||
return (0.0f != m_buttons->controls.back()->control_ref->State());
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
|
||||
void Spy(Wiimote* wm_, const void* data_, int size_)
|
||||
void Spy(Wiimote* wm_, const void* data_, size_t size_)
|
||||
{
|
||||
#if 0
|
||||
// enable log
|
||||
@@ -1275,7 +1275,7 @@ void Wiimote::DoState(PointerWrap& p)
|
||||
else
|
||||
{
|
||||
std::queue<ReadRequest> tmp_queue(m_read_requests);
|
||||
size = m_read_requests.size();
|
||||
size = (u32)(m_read_requests.size());
|
||||
p.Do(size);
|
||||
while (!tmp_queue.empty())
|
||||
{
|
||||
|
||||
@@ -765,7 +765,7 @@ void Wiimote::Update()
|
||||
if (-1 == rptf_size)
|
||||
{
|
||||
std::copy(rpt.begin(), rpt.end(), data);
|
||||
rptf_size = rpt.size();
|
||||
rptf_size = (s8)(rpt.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ inline double trim(double a)
|
||||
class Wiimote : public ControllerEmu
|
||||
{
|
||||
friend class WiimoteReal::Wiimote;
|
||||
friend void Spy(Wiimote* wm_, const void* data_, int size_);
|
||||
friend void Spy(Wiimote* wm_, const void* data_, size_t size_);
|
||||
public:
|
||||
|
||||
enum
|
||||
@@ -245,7 +245,7 @@ private:
|
||||
} m_reg_speaker;
|
||||
};
|
||||
|
||||
void Spy(Wiimote* wm_, const void* data_, int size_);
|
||||
void Spy(Wiimote* wm_, const void* data_, size_t size_);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ int Wiimote::IORead(u8* buf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Wiimote::IOWrite(const u8* buf, int len)
|
||||
int Wiimote::IOWrite(const u8* buf, size_t len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -263,9 +263,9 @@ int Wiimote::IORead(u8* buf)
|
||||
return r;
|
||||
}
|
||||
|
||||
int Wiimote::IOWrite(u8 const* buf, int len)
|
||||
int Wiimote::IOWrite(u8 const* buf, size_t len)
|
||||
{
|
||||
return write(int_sock, buf, len);
|
||||
return write(int_sock, buf, (int)len);
|
||||
}
|
||||
|
||||
}; // WiimoteReal
|
||||
|
||||
@@ -140,7 +140,7 @@ namespace WiimoteReal
|
||||
{
|
||||
|
||||
|
||||
int _IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, enum win_bt_stack_t &stack, const u8* buf, int len);
|
||||
int _IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, enum win_bt_stack_t &stack, const u8* buf, size_t len);
|
||||
int _IORead(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read, u8* buf, int index);
|
||||
void _IOWakeup(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read);
|
||||
|
||||
@@ -247,7 +247,7 @@ void WiimoteScanner::FindWiimotes(std::vector<Wiimote*> & found_wiimotes, Wiimot
|
||||
// SLEEP(2000);
|
||||
|
||||
}
|
||||
int CheckDeviceType_Write(HANDLE &dev_handle, const u8* buf, int size, int attempts)
|
||||
int CheckDeviceType_Write(HANDLE &dev_handle, const u8* buf, size_t size, int attempts)
|
||||
{
|
||||
OVERLAPPED hid_overlap_write = OVERLAPPED();
|
||||
hid_overlap_write.hEvent = CreateEvent(NULL, true, false, NULL);
|
||||
@@ -641,7 +641,7 @@ int Wiimote::IORead(u8* buf)
|
||||
}
|
||||
|
||||
|
||||
int _IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, enum win_bt_stack_t &stack, const u8* buf, int len)
|
||||
int _IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, enum win_bt_stack_t &stack, const u8* buf, size_t len)
|
||||
{
|
||||
WiimoteEmu::Spy(NULL, buf, len);
|
||||
|
||||
@@ -663,7 +663,7 @@ int _IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, enum win_bt_stac
|
||||
}
|
||||
case MSBT_STACK_MS:
|
||||
{
|
||||
auto result = HidD_SetOutputReport(dev_handle, const_cast<u8*>(buf) + 1, len - 1);
|
||||
auto result = HidD_SetOutputReport(dev_handle, const_cast<u8*>(buf) + 1, (ULONG)(len - 1));
|
||||
//FlushFileBuffers(dev_handle);
|
||||
|
||||
if (!result)
|
||||
@@ -715,7 +715,7 @@ int _IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, enum win_bt_stac
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Wiimote::IOWrite(const u8* buf, int len)
|
||||
int Wiimote::IOWrite(const u8* buf, size_t len)
|
||||
{
|
||||
return _IOWrite(dev_handle, hid_overlap_write, stack, buf, len);
|
||||
}
|
||||
|
||||
@@ -310,14 +310,14 @@ int Wiimote::IORead(unsigned char *buf)
|
||||
return inputlen;
|
||||
}
|
||||
|
||||
int Wiimote::IOWrite(const unsigned char *buf, int len)
|
||||
int Wiimote::IOWrite(const unsigned char *buf, size_t len)
|
||||
{
|
||||
IOReturn ret;
|
||||
|
||||
if (!IsConnected())
|
||||
return 0;
|
||||
|
||||
ret = [ichan writeAsync: const_cast<void*>((void *)buf) length: len refcon: nil];
|
||||
ret = [ichan writeAsync: const_cast<void*>((void *)buf) length: (int)len refcon: nil];
|
||||
|
||||
if (ret == kIOReturnSuccess)
|
||||
return len;
|
||||
|
||||
@@ -239,7 +239,9 @@ bool Wiimote::Write()
|
||||
IOWrite(rpt.data(), rpt.size());
|
||||
|
||||
if (is_speaker_data)
|
||||
{
|
||||
m_last_audio_report.Update();
|
||||
}
|
||||
|
||||
m_write_reports.Pop();
|
||||
return true;
|
||||
@@ -293,8 +295,10 @@ void Wiimote::Update()
|
||||
|
||||
// Send the report
|
||||
if (!rpt.empty() && m_channel > 0)
|
||||
Core::Callback_WiimoteInterruptChannel(index, m_channel,
|
||||
rpt.data(), rpt.size());
|
||||
{
|
||||
Core::Callback_WiimoteInterruptChannel(index, m_channel,
|
||||
rpt.data(), (u32)rpt.size());
|
||||
}
|
||||
}
|
||||
|
||||
void Wiimote::Prepare(int _index)
|
||||
|
||||
@@ -106,7 +106,7 @@ private:
|
||||
void WriteReport(Report rpt);
|
||||
|
||||
int IORead(u8* buf);
|
||||
int IOWrite(u8 const* buf, int len);
|
||||
int IOWrite(u8 const* buf, size_t len);
|
||||
void IOWakeup();
|
||||
|
||||
void ThreadFunc();
|
||||
|
||||
@@ -83,7 +83,7 @@ static u64 last_reply_time;
|
||||
void EnqueReplyCallback(u64 userdata, int)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(s_reply_queue);
|
||||
reply_queue.push_back(userdata);
|
||||
reply_queue.push_back((u32)userdata);
|
||||
}
|
||||
|
||||
void Init()
|
||||
@@ -546,7 +546,9 @@ void ExecuteCommand(u32 _Address)
|
||||
const s64 ticks_til_last_reply = last_reply_time - CoreTiming::GetTicks();
|
||||
|
||||
if (ticks_til_last_reply > 0)
|
||||
reply_delay = ticks_til_last_reply;
|
||||
{
|
||||
reply_delay = (int)ticks_til_last_reply;
|
||||
}
|
||||
|
||||
last_reply_time = CoreTiming::GetTicks() + reply_delay;
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ void CWII_IPC_HLE_Device_es::DoState(PointerWrap& p)
|
||||
p.Do(m_AccessIdentID);
|
||||
p.Do(m_TitleIDs);
|
||||
|
||||
u32 Count = m_ContentAccessMap.size();
|
||||
u32 Count = (u32)(m_ContentAccessMap.size());
|
||||
p.Do(Count);
|
||||
|
||||
u32 CFD, Position;
|
||||
|
||||
@@ -571,7 +571,7 @@ void CWII_IPC_HLE_Device_fs::DoState(PointerWrap& p)
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 size = entry.size;
|
||||
u32 size = (u32)entry.size;
|
||||
p.Do(size);
|
||||
|
||||
File::IOFile handle(entry.physicalName, "rb");
|
||||
|
||||
@@ -385,12 +385,12 @@ void CWII_IPC_HLE_Device_hid::FillOutDevices(u32 BufferOut, u32 BufferOutSize)
|
||||
Memory::WriteBigEData((const u8*)&wii_device, OffsetBuffer, Align(wii_device.bLength, 4));
|
||||
OffsetBuffer += Align(wii_device.bLength, 4);
|
||||
bool deviceValid = true;
|
||||
bool isHID = false;
|
||||
|
||||
for (c = 0; deviceValid && c < desc.bNumConfigurations; c++)
|
||||
{
|
||||
struct libusb_config_descriptor *config = NULL;
|
||||
int cRet = libusb_get_config_descriptor(device, c, &config);
|
||||
|
||||
// do not try to use usb devices with more than one interface, games can crash
|
||||
if(cRet == 0 && config->bNumInterfaces <= MAX_HID_INTERFACES)
|
||||
{
|
||||
@@ -402,10 +402,14 @@ void CWII_IPC_HLE_Device_hid::FillOutDevices(u32 BufferOut, u32 BufferOutSize)
|
||||
for (ic = 0; ic < config->bNumInterfaces; ic++)
|
||||
{
|
||||
const struct libusb_interface *interfaceContainer = &config->interface[ic];
|
||||
|
||||
for (i = 0; i < interfaceContainer->num_altsetting; i++)
|
||||
{
|
||||
const struct libusb_interface_descriptor *interface = &interfaceContainer->altsetting[i];
|
||||
|
||||
if (interface->bInterfaceClass == LIBUSB_CLASS_HID)
|
||||
isHID = true;
|
||||
|
||||
WiiHIDInterfaceDescriptor wii_interface;
|
||||
ConvertInterfaceToWii(&wii_interface, interface);
|
||||
Memory::WriteBigEData((const u8*)&wii_interface, OffsetBuffer, Align(wii_interface.bLength, 4));
|
||||
@@ -435,6 +439,12 @@ void CWII_IPC_HLE_Device_hid::FillOutDevices(u32 BufferOut, u32 BufferOutSize)
|
||||
}
|
||||
} // configs
|
||||
|
||||
if (!isHID)
|
||||
{
|
||||
deviceValid = false;
|
||||
OffsetBuffer = OffsetStart;
|
||||
}
|
||||
|
||||
if (deviceValid)
|
||||
{
|
||||
Memory::Write_U32(OffsetBuffer-OffsetStart, OffsetStart); // fill in length
|
||||
|
||||
@@ -866,7 +866,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRoleChange(bdaddr_t _bd, bool
|
||||
|
||||
bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventNumberOfCompletedPackets()
|
||||
{
|
||||
SQueuedEvent Event(sizeof(hci_event_hdr_t) + sizeof(hci_num_compl_pkts_ep) + sizeof(hci_num_compl_pkts_info) * m_WiiMotes.size(), 0);
|
||||
SQueuedEvent Event((u32)(sizeof(hci_event_hdr_t) + sizeof(hci_num_compl_pkts_ep) + (sizeof(hci_num_compl_pkts_info) * m_WiiMotes.size())), 0);
|
||||
|
||||
INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventNumberOfCompletedPackets");
|
||||
|
||||
|
||||
@@ -445,10 +445,11 @@ void NetPlayClient::SendWiimoteState(const PadMapping in_game_pad, const NetWiim
|
||||
sf::Packet spac;
|
||||
spac << (MessageId)NP_MSG_WIIMOTE_DATA;
|
||||
spac << in_game_pad;
|
||||
u8 size = nw.size();
|
||||
spac << size;
|
||||
for (unsigned int i = 0; i < size; ++i)
|
||||
spac << nw.data()[i];
|
||||
spac << (u8)nw.size();
|
||||
for (auto it : nw)
|
||||
{
|
||||
spac << it;
|
||||
}
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
|
||||
m_socket.Send(spac);
|
||||
|
||||
@@ -153,7 +153,7 @@ unsigned int NetPlayServer::OnConnect(sf::SocketTCP& socket)
|
||||
rpac >> player.name;
|
||||
|
||||
// give new client first available id
|
||||
player.pid = m_players.size() + 1;
|
||||
player.pid = (PlayerId)(m_players.size() + 1);
|
||||
|
||||
// try to automatically assign new user a pad
|
||||
for (unsigned int m = 0; m < 4; ++m)
|
||||
@@ -435,12 +435,14 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, sf::SocketTCP& socket)
|
||||
|
||||
case NP_MSG_PONG :
|
||||
{
|
||||
const u32 ping = m_ping_timer.GetTimeElapsed();
|
||||
const u32 ping = (u32)m_ping_timer.GetTimeElapsed();
|
||||
u32 ping_key = 0;
|
||||
packet >> ping_key;
|
||||
|
||||
if (m_ping_key == ping_key)
|
||||
{
|
||||
player.ping = ping;
|
||||
}
|
||||
|
||||
sf::Packet spac;
|
||||
spac << (MessageId)NP_MSG_PLAYER_PING_DATA;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#ifndef _INTERPRETER_FPUTILS_H
|
||||
#define _INTERPRETER_FPUTILS_H
|
||||
|
||||
#include "CPUDetect.h"
|
||||
#include "Interpreter.h"
|
||||
#include "MathUtil.h"
|
||||
|
||||
@@ -69,28 +70,22 @@ inline void UpdateFPSCR()
|
||||
|
||||
inline double ForceSingle(double _x)
|
||||
{
|
||||
//if (FPSCR.RN != 0)
|
||||
// PanicAlert("RN = %d at %x", (int)FPSCR.RN, PC);
|
||||
if (FPSCR.NI)
|
||||
_x = FlushToZeroAsFloat(_x);
|
||||
|
||||
double x = static_cast<float>(_x);
|
||||
|
||||
// convert to float...
|
||||
float x = _x;
|
||||
if (!cpu_info.bFlushToZero && FPSCR.NI)
|
||||
{
|
||||
x = FlushToZero(x);
|
||||
}
|
||||
// ...and back to double:
|
||||
return x;
|
||||
}
|
||||
|
||||
inline double ForceDouble(double d)
|
||||
{
|
||||
//if (FPSCR.RN != 0)
|
||||
// PanicAlert("RN = %d at %x", (int)FPSCR.RN, PC);
|
||||
|
||||
//if (FPSCR.NI)
|
||||
//{
|
||||
// IntDouble x; x.d = d;
|
||||
//if ((x.i & DOUBLE_EXP) == 0)
|
||||
// x.i &= DOUBLE_SIGN; // turn into signed zero
|
||||
// return x.d;
|
||||
//}
|
||||
if (!cpu_info.bFlushToZero && FPSCR.NI)
|
||||
{
|
||||
d = FlushToZero(d);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,15 +48,8 @@ static void FPSCRtoFPUSettings(UReg_FPSCR fp)
|
||||
// Pokemon Colosseum does this. Gah.
|
||||
}
|
||||
|
||||
// Also corresponding SSE rounding mode setting
|
||||
if (FPSCR.NI)
|
||||
{
|
||||
// Either one of these two breaks Beyond Good & Evil.
|
||||
// if (cpu_info.bSSSE3)
|
||||
// csr |= DAZ;
|
||||
// csr |= FTZ;
|
||||
}
|
||||
FPURoundMode::SetSIMDMode(FPSCR.RN);
|
||||
// Set SSE rounding mode and denormal handling
|
||||
FPURoundMode::SetSIMDMode(FPSCR.RN, FPSCR.NI);
|
||||
}
|
||||
|
||||
void Interpreter::mtfsb0x(UGeckoInstruction _inst)
|
||||
|
||||
@@ -276,7 +276,7 @@ void Jit64::Cleanup()
|
||||
ABI_CallFunctionCCC((void *)&PowerPC::UpdatePerformanceMonitor, js.downcountAmount, jit->js.numLoadStoreInst, jit->js.numFloatingPointInst);
|
||||
}
|
||||
|
||||
void Jit64::WriteExit(u32 destination, int exit_num)
|
||||
void Jit64::WriteExit(u32 destination)
|
||||
{
|
||||
Cleanup();
|
||||
|
||||
@@ -284,8 +284,9 @@ void Jit64::WriteExit(u32 destination, int exit_num)
|
||||
|
||||
//If nobody has taken care of this yet (this can be removed when all branches are done)
|
||||
JitBlock *b = js.curBlock;
|
||||
b->exitAddress[exit_num] = destination;
|
||||
b->exitPtrs[exit_num] = GetWritableCodePtr();
|
||||
JitBlock::LinkData linkData;
|
||||
linkData.exitAddress = destination;
|
||||
linkData.exitPtrs = GetWritableCodePtr();
|
||||
|
||||
// Link opportunity!
|
||||
if (jo.enableBlocklink)
|
||||
@@ -295,12 +296,14 @@ void Jit64::WriteExit(u32 destination, int exit_num)
|
||||
{
|
||||
// It exists! Joy of joy!
|
||||
JMP(blocks.GetBlock(block)->checkedEntry, true);
|
||||
b->linkStatus[exit_num] = true;
|
||||
linkData.linkStatus = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
MOV(32, M(&PC), Imm32(destination));
|
||||
JMP(asm_routines.dispatcher, true);
|
||||
|
||||
b->linkData.push_back(linkData);
|
||||
}
|
||||
|
||||
void Jit64::WriteExitDestInEAX()
|
||||
@@ -625,7 +628,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
|
||||
FixupBranch noBreakpoint = J_CC(CC_Z);
|
||||
|
||||
WriteExit(ops[i].address, 0);
|
||||
WriteExit(ops[i].address);
|
||||
SetJumpTarget(noBreakpoint);
|
||||
}
|
||||
|
||||
@@ -707,7 +710,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
{
|
||||
gpr.Flush(FLUSH_ALL);
|
||||
fpr.Flush(FLUSH_ALL);
|
||||
WriteExit(nextPC, 0);
|
||||
WriteExit(nextPC);
|
||||
}
|
||||
|
||||
b->flags = js.block_flags;
|
||||
|
||||
@@ -99,7 +99,7 @@ public:
|
||||
|
||||
// Utilities for use by opcodes
|
||||
|
||||
void WriteExit(u32 destination, int exit_num);
|
||||
void WriteExit(u32 destination);
|
||||
void WriteExitDestInEAX();
|
||||
void WriteExceptionExit();
|
||||
void WriteExternalExceptionExit();
|
||||
@@ -182,7 +182,7 @@ public:
|
||||
void ps_sum(UGeckoInstruction inst);
|
||||
void ps_muls(UGeckoInstruction inst);
|
||||
|
||||
void fp_arith_s(UGeckoInstruction inst);
|
||||
void fp_arith(UGeckoInstruction inst);
|
||||
void frsqrtex(UGeckoInstruction inst);
|
||||
|
||||
void fcmpx(UGeckoInstruction inst);
|
||||
|
||||
@@ -320,12 +320,12 @@ static GekkoOPTemplate table31_2[] =
|
||||
|
||||
static GekkoOPTemplate table59[] =
|
||||
{
|
||||
{18, &Jit64::Default}, //{"fdivsx", OPTYPE_FPU, FL_RC_BIT_F, 16}},
|
||||
{20, &Jit64::fp_arith_s}, //"fsubsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{21, &Jit64::fp_arith_s}, //"faddsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{18, &Jit64::fp_arith}, //{"fdivsx", OPTYPE_FPU, FL_RC_BIT_F, 16}},
|
||||
{20, &Jit64::fp_arith}, //"fsubsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{21, &Jit64::fp_arith}, //"faddsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
// {22, &Jit64::Default}, //"fsqrtsx", OPTYPE_FPU, FL_RC_BIT_F}}, // Not implemented on gekko
|
||||
{24, &Jit64::Default}, //"fresx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{25, &Jit64::fp_arith_s}, //"fmulsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{25, &Jit64::fp_arith}, //"fmulsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{28, &Jit64::fmaddXX}, //"fmsubsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{29, &Jit64::fmaddXX}, //"fmaddsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{30, &Jit64::fmaddXX}, //"fnmsubsx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
@@ -354,12 +354,12 @@ static GekkoOPTemplate table63[] =
|
||||
|
||||
static GekkoOPTemplate table63_2[] =
|
||||
{
|
||||
{18, &Jit64::Default}, //"fdivx", OPTYPE_FPU, FL_RC_BIT_F, 30}},
|
||||
{20, &Jit64::Default}, //"fsubx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{21, &Jit64::Default}, //"faddx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{18, &Jit64::fp_arith}, //"fdivx", OPTYPE_FPU, FL_RC_BIT_F, 30}},
|
||||
{20, &Jit64::fp_arith}, //"fsubx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{21, &Jit64::fp_arith}, //"faddx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{22, &Jit64::Default}, //"fsqrtx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{23, &Jit64::Default}, //"fselx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{25, &Jit64::fp_arith_s}, //"fmulx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{25, &Jit64::fp_arith}, //"fmulx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{26, &Jit64::frsqrtex}, //"frsqrtex", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{28, &Jit64::fmaddXX}, //"fmsubx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
{29, &Jit64::fmaddXX}, //"fmaddx", OPTYPE_FPU, FL_RC_BIT_F}},
|
||||
|
||||
@@ -166,7 +166,7 @@ int RegCache::SanityCheck() const
|
||||
|
||||
void RegCache::DiscardRegContentsIfCached(int preg)
|
||||
{
|
||||
if (regs[preg].away && regs[preg].location.IsSimpleReg())
|
||||
if (IsBound(preg))
|
||||
{
|
||||
X64Reg xr = regs[preg].location.GetSimpleReg();
|
||||
xregs[xr].free = true;
|
||||
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
const OpArg &R(int preg) const {return regs[preg].location;}
|
||||
X64Reg RX(int preg) const
|
||||
{
|
||||
if (regs[preg].away && regs[preg].location.IsSimpleReg())
|
||||
if (IsBound(preg))
|
||||
return regs[preg].location.GetSimpleReg();
|
||||
PanicAlert("Not so simple - %i", preg);
|
||||
return (X64Reg)-1;
|
||||
@@ -111,6 +111,11 @@ public:
|
||||
return xregs[xreg].free && !xlocks[xreg];
|
||||
}
|
||||
|
||||
bool IsBound(int preg) const
|
||||
{
|
||||
return regs[preg].away && regs[preg].location.IsSimpleReg();
|
||||
}
|
||||
|
||||
|
||||
X64Reg GetFreeXReg();
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ void Jit64::bx(UGeckoInstruction inst)
|
||||
// make idle loops go faster
|
||||
js.downcountAmount += 8;
|
||||
}
|
||||
WriteExit(destination, 0);
|
||||
WriteExit(destination);
|
||||
}
|
||||
|
||||
// TODO - optimize to hell and beyond
|
||||
@@ -136,13 +136,13 @@ void Jit64::bcx(UGeckoInstruction inst)
|
||||
destination = SignExt16(inst.BD << 2);
|
||||
else
|
||||
destination = js.compilerPC + SignExt16(inst.BD << 2);
|
||||
WriteExit(destination, 0);
|
||||
WriteExit(destination);
|
||||
|
||||
if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0)
|
||||
SetJumpTarget( pConditionDontBranch );
|
||||
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
|
||||
SetJumpTarget( pCTRDontBranch );
|
||||
WriteExit(js.compilerPC + 4, 1);
|
||||
WriteExit(js.compilerPC + 4);
|
||||
}
|
||||
|
||||
void Jit64::bcctrx(UGeckoInstruction inst)
|
||||
@@ -190,7 +190,7 @@ void Jit64::bcctrx(UGeckoInstruction inst)
|
||||
WriteExitDestInEAX();
|
||||
// Would really like to continue the block here, but it ends. TODO.
|
||||
SetJumpTarget(b);
|
||||
WriteExit(js.compilerPC + 4, 1);
|
||||
WriteExit(js.compilerPC + 4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,5 +245,5 @@ void Jit64::bclrx(UGeckoInstruction inst)
|
||||
SetJumpTarget( pConditionDontBranch );
|
||||
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
|
||||
SetJumpTarget( pCTRDontBranch );
|
||||
WriteExit(js.compilerPC + 4, 1);
|
||||
WriteExit(js.compilerPC + 4);
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ void Jit64::fp_tri_op(int d, int a, int b, bool reversible, bool single,
|
||||
fpr.UnlockAll();
|
||||
}
|
||||
|
||||
void Jit64::fp_arith_s(UGeckoInstruction inst)
|
||||
void Jit64::fp_arith(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITFloatingPointOff)
|
||||
@@ -106,7 +106,7 @@ void Jit64::fp_arith_s(UGeckoInstruction inst)
|
||||
case 21: fp_tri_op(inst.FD, inst.FA, inst.FB, true, single, &XEmitter::ADDSD, &XEmitter::VADDSD); break; //add
|
||||
case 25: fp_tri_op(inst.FD, inst.FA, inst.FC, true, single, &XEmitter::MULSD, &XEmitter::VMULSD); break; //mul
|
||||
default:
|
||||
_assert_msg_(DYNA_REC, 0, "fp_arith_s WTF!!!");
|
||||
_assert_msg_(DYNA_REC, 0, "fp_arith WTF!!!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,16 +224,28 @@ void Jit64::fmrx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITFloatingPointOff)
|
||||
if (inst.Rc) {
|
||||
if (inst.Rc)
|
||||
{
|
||||
Default(inst); return;
|
||||
}
|
||||
int d = inst.FD;
|
||||
int b = inst.FB;
|
||||
fpr.Lock(b, d);
|
||||
fpr.BindToRegister(d, d == b, true);
|
||||
MOVSD(XMM0, fpr.R(b));
|
||||
MOVSD(fpr.R(d), XMM0);
|
||||
fpr.UnlockAll();
|
||||
if (d != b)
|
||||
{
|
||||
fpr.Lock(b, d);
|
||||
|
||||
// we don't need to load d, but if it already is, it must be marked as dirty
|
||||
if (fpr.IsBound(d))
|
||||
{
|
||||
fpr.BindToRegister(d);
|
||||
}
|
||||
fpr.BindToRegister(b, true, false);
|
||||
|
||||
// caveat: the order of ModRM:r/m, ModRM:reg is deliberate!
|
||||
// "MOVSD reg, mem" zeros out the upper half of the destination register
|
||||
MOVSD(fpr.R(d), fpr.RX(b));
|
||||
fpr.UnlockAll();
|
||||
}
|
||||
}
|
||||
|
||||
void Jit64::fcmpx(UGeckoInstruction inst)
|
||||
|
||||
@@ -400,7 +400,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
||||
destination = SignExt16(js.next_inst.BD << 2);
|
||||
else
|
||||
destination = js.next_compilerPC + SignExt16(js.next_inst.BD << 2);
|
||||
WriteExit(destination, 0);
|
||||
WriteExit(destination);
|
||||
}
|
||||
else if ((js.next_inst.OPCD == 19) && (js.next_inst.SUBOP10 == 528)) // bcctrx
|
||||
{
|
||||
@@ -424,7 +424,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteExit(js.next_compilerPC + 4, 0);
|
||||
WriteExit(js.next_compilerPC + 4);
|
||||
}
|
||||
|
||||
js.cancel = true;
|
||||
@@ -507,7 +507,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
||||
destination = SignExt16(js.next_inst.BD << 2);
|
||||
else
|
||||
destination = js.next_compilerPC + SignExt16(js.next_inst.BD << 2);
|
||||
WriteExit(destination, 0);
|
||||
WriteExit(destination);
|
||||
}
|
||||
else if ((js.next_inst.OPCD == 19) && (js.next_inst.SUBOP10 == 528)) // bcctrx
|
||||
{
|
||||
@@ -534,7 +534,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
||||
if (!!(4 & test_bit) == condition) SetJumpTarget(continue2);
|
||||
if (!!(2 & test_bit) == condition) SetJumpTarget(continue1);
|
||||
|
||||
WriteExit(js.next_compilerPC + 4, 1);
|
||||
WriteExit(js.next_compilerPC + 4);
|
||||
|
||||
js.cancel = true;
|
||||
}
|
||||
@@ -2221,5 +2221,5 @@ void Jit64::twx(UGeckoInstruction inst)
|
||||
SetJumpTarget(exit3);
|
||||
SetJumpTarget(exit4);
|
||||
SetJumpTarget(exit5);
|
||||
WriteExit(js.compilerPC + 4, 1);
|
||||
WriteExit(js.compilerPC + 4);
|
||||
}
|
||||
|
||||
@@ -480,5 +480,5 @@ void Jit64::stmw(UGeckoInstruction inst)
|
||||
void Jit64::icbi(UGeckoInstruction inst)
|
||||
{
|
||||
Default(inst);
|
||||
WriteExit(js.compilerPC + 4, 0);
|
||||
WriteExit(js.compilerPC + 4);
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ void Jit64::mtmsr(UGeckoInstruction inst)
|
||||
SetJumpTarget(noExceptionsPending);
|
||||
SetJumpTarget(eeDisabled);
|
||||
|
||||
WriteExit(js.compilerPC + 4, 0);
|
||||
WriteExit(js.compilerPC + 4);
|
||||
|
||||
js.firstFPInstructionFound = false;
|
||||
}
|
||||
|
||||
@@ -552,7 +552,8 @@ static void regEmitICmpInst(RegInfo& RI, InstLoc I, CCFlags flag) {
|
||||
|
||||
static void regWriteExit(RegInfo& RI, InstLoc dest) {
|
||||
if (isImm(*dest)) {
|
||||
RI.Jit->WriteExit(RI.Build->GetImmValue(dest), RI.exitNumber++);
|
||||
RI.exitNumber++;
|
||||
RI.Jit->WriteExit(RI.Build->GetImmValue(dest));
|
||||
} else {
|
||||
RI.Jit->WriteExitDestInOpArg(regLocForInst(RI, dest));
|
||||
}
|
||||
@@ -564,7 +565,7 @@ static bool checkIsSNAN() {
|
||||
return MathUtil::IsSNAN(isSNANTemp[0][0]) || MathUtil::IsSNAN(isSNANTemp[1][0]);
|
||||
}
|
||||
|
||||
static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit) {
|
||||
static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, u32 exitAddress) {
|
||||
//printf("Writing block: %x\n", js.blockStart);
|
||||
RegInfo RI(Jit, ibuild->getFirstInst(), ibuild->getNumInsts());
|
||||
RI.Build = ibuild;
|
||||
@@ -1791,7 +1792,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit) {
|
||||
Jit->ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints));
|
||||
Jit->TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
|
||||
FixupBranch noBreakpoint = Jit->J_CC(CC_Z);
|
||||
Jit->WriteExit(InstLoc, 0);
|
||||
Jit->WriteExit(InstLoc);
|
||||
Jit->SetJumpTarget(noBreakpoint);
|
||||
break;
|
||||
}
|
||||
@@ -1819,10 +1820,10 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit) {
|
||||
}
|
||||
}
|
||||
|
||||
Jit->WriteExit(jit->js.curBlock->exitAddress[0], 0);
|
||||
Jit->WriteExit(exitAddress);
|
||||
Jit->UD2();
|
||||
}
|
||||
|
||||
void JitIL::WriteCode() {
|
||||
DoWriteCode(&ibuild, this);
|
||||
void JitIL::WriteCode(u32 exitAddress) {
|
||||
DoWriteCode(&ibuild, this, exitAddress);
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ void JitIL::Cleanup()
|
||||
ABI_CallFunctionCCC((void *)&PowerPC::UpdatePerformanceMonitor, js.downcountAmount, jit->js.numLoadStoreInst, jit->js.numFloatingPointInst);
|
||||
}
|
||||
|
||||
void JitIL::WriteExit(u32 destination, int exit_num)
|
||||
void JitIL::WriteExit(u32 destination)
|
||||
{
|
||||
Cleanup();
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bJITILTimeProfiling) {
|
||||
@@ -391,8 +391,9 @@ void JitIL::WriteExit(u32 destination, int exit_num)
|
||||
|
||||
//If nobody has taken care of this yet (this can be removed when all branches are done)
|
||||
JitBlock *b = js.curBlock;
|
||||
b->exitAddress[exit_num] = destination;
|
||||
b->exitPtrs[exit_num] = GetWritableCodePtr();
|
||||
JitBlock::LinkData linkData;
|
||||
linkData.exitAddress = destination;
|
||||
linkData.exitPtrs = GetWritableCodePtr();
|
||||
|
||||
// Link opportunity!
|
||||
int block = blocks.GetBlockNumberFromStartAddress(destination);
|
||||
@@ -400,13 +401,14 @@ void JitIL::WriteExit(u32 destination, int exit_num)
|
||||
{
|
||||
// It exists! Joy of joy!
|
||||
JMP(blocks.GetBlock(block)->checkedEntry, true);
|
||||
b->linkStatus[exit_num] = true;
|
||||
linkData.linkStatus = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
MOV(32, M(&PC), Imm32(destination));
|
||||
JMP(asm_routines.dispatcher, true);
|
||||
}
|
||||
b->linkData.push_back(linkData);
|
||||
}
|
||||
|
||||
void JitIL::WriteExitDestInOpArg(const Gen::OpArg& arg)
|
||||
@@ -541,14 +543,16 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
|
||||
// Analyze the block, collect all instructions it is made of (including inlining,
|
||||
// if that is enabled), reorder instructions for optimal performance, and join joinable instructions.
|
||||
b->exitAddress[0] = em_address;
|
||||
u32 exitAddress = em_address;
|
||||
|
||||
u32 merged_addresses[32];
|
||||
const int capacity_of_merged_addresses = sizeof(merged_addresses) / sizeof(merged_addresses[0]);
|
||||
int size_of_merged_addresses = 0;
|
||||
if (!memory_exception)
|
||||
{
|
||||
// If there is a memory exception inside a block (broken_block==true), compile up to that instruction.
|
||||
b->exitAddress[0] = PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, broken_block, code_buf, blockSize, merged_addresses, capacity_of_merged_addresses, size_of_merged_addresses);
|
||||
// TODO
|
||||
exitAddress = PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, broken_block, code_buf, blockSize, merged_addresses, capacity_of_merged_addresses, size_of_merged_addresses);
|
||||
}
|
||||
PPCAnalyst::CodeOp *ops = code_buf->codebuffer;
|
||||
|
||||
@@ -707,7 +711,7 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||
}
|
||||
|
||||
// Perform actual code generation
|
||||
WriteCode();
|
||||
WriteCode(exitAddress);
|
||||
|
||||
b->codeSize = (u32)(GetCodePtr() - normalEntry);
|
||||
b->originalSize = size;
|
||||
|
||||
@@ -105,7 +105,7 @@ public:
|
||||
|
||||
// Utilities for use by opcodes
|
||||
|
||||
void WriteExit(u32 destination, int exit_num);
|
||||
void WriteExit(u32 destination);
|
||||
void WriteExitDestInOpArg(const Gen::OpArg& arg);
|
||||
void WriteExceptionExit();
|
||||
void WriteRfiExitDestInOpArg(const Gen::OpArg& arg);
|
||||
@@ -121,7 +121,7 @@ public:
|
||||
void regimmop(int d, int a, bool binary, u32 value, Operation doop, void (Gen::XEmitter::*op)(int, const Gen::OpArg&, const Gen::OpArg&), bool Rc = false, bool carry = false);
|
||||
void fp_tri_op(int d, int a, int b, bool reversible, bool dupe, void (Gen::XEmitter::*op)(Gen::X64Reg, Gen::OpArg));
|
||||
|
||||
void WriteCode();
|
||||
void WriteCode(u32 exitAddress);
|
||||
|
||||
// OPCODES
|
||||
void unknown_instruction(UGeckoInstruction _inst) override;
|
||||
|
||||
@@ -186,15 +186,16 @@ void JitArm::WriteExceptionExit()
|
||||
MOVI2R(A, (u32)asm_routines.testExceptions);
|
||||
B(A);
|
||||
}
|
||||
void JitArm::WriteExit(u32 destination, int exit_num)
|
||||
void JitArm::WriteExit(u32 destination)
|
||||
{
|
||||
Cleanup();
|
||||
|
||||
DoDownCount();
|
||||
//If nobody has taken care of this yet (this can be removed when all branches are done)
|
||||
JitBlock *b = js.curBlock;
|
||||
b->exitAddress[exit_num] = destination;
|
||||
b->exitPtrs[exit_num] = GetWritableCodePtr();
|
||||
JitBlock::LinkData linkData;
|
||||
linkData.exitAddress = destination;
|
||||
linkData.exitPtrs = GetWritableCodePtr();
|
||||
|
||||
// Link opportunity!
|
||||
int block = blocks.GetBlockNumberFromStartAddress(destination);
|
||||
@@ -202,7 +203,7 @@ void JitArm::WriteExit(u32 destination, int exit_num)
|
||||
{
|
||||
// It exists! Joy of joy!
|
||||
B(blocks.GetBlock(block)->checkedEntry);
|
||||
b->linkStatus[exit_num] = true;
|
||||
linkData.linkStatus = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -212,6 +213,8 @@ void JitArm::WriteExit(u32 destination, int exit_num)
|
||||
MOVI2R(A, (u32)asm_routines.dispatcher);
|
||||
B(A);
|
||||
}
|
||||
|
||||
b->linkData.push_back(linkData);
|
||||
}
|
||||
|
||||
void STACKALIGN JitArm::Run()
|
||||
@@ -496,7 +499,7 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo
|
||||
if (broken_block)
|
||||
{
|
||||
printf("Broken Block going to 0x%08x\n", nextPC);
|
||||
WriteExit(nextPC, 0);
|
||||
WriteExit(nextPC);
|
||||
}
|
||||
|
||||
b->flags = js.block_flags;
|
||||
|
||||
@@ -109,7 +109,7 @@ public:
|
||||
|
||||
// Utilities for use by opcodes
|
||||
|
||||
void WriteExit(u32 destination, int exit_num);
|
||||
void WriteExit(u32 destination);
|
||||
void WriteExitDestInR(ARMReg Reg);
|
||||
void WriteRfiExitDestInR(ARMReg Reg);
|
||||
void WriteExceptionExit();
|
||||
|
||||
@@ -135,9 +135,11 @@ void JitArm::bx(UGeckoInstruction inst)
|
||||
else
|
||||
destination = js.compilerPC + SignExt26(inst.LI << 2);
|
||||
#ifdef ACID_TEST
|
||||
// TODO: Not implemented yet.
|
||||
//if (inst.LK)
|
||||
//AND(32, M(&PowerPC::ppcState.cr), Imm32(~(0xFF000000)));
|
||||
if (inst.LK)
|
||||
{
|
||||
MOV(R14, 0);
|
||||
STRB(R14, R9, PPCSTATE_OFF(cr_fast[0]));
|
||||
}
|
||||
#endif
|
||||
if (destination == js.compilerPC)
|
||||
{
|
||||
@@ -152,7 +154,7 @@ void JitArm::bx(UGeckoInstruction inst)
|
||||
MOVI2R(R14, (u32)asm_routines.testExceptions);
|
||||
B(R14);
|
||||
}
|
||||
WriteExit(destination, 0);
|
||||
WriteExit(destination);
|
||||
}
|
||||
|
||||
void JitArm::bcx(UGeckoInstruction inst)
|
||||
@@ -207,14 +209,14 @@ void JitArm::bcx(UGeckoInstruction inst)
|
||||
destination = SignExt16(inst.BD << 2);
|
||||
else
|
||||
destination = js.compilerPC + SignExt16(inst.BD << 2);
|
||||
WriteExit(destination, 0);
|
||||
WriteExit(destination);
|
||||
|
||||
if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0)
|
||||
SetJumpTarget( pConditionDontBranch );
|
||||
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
|
||||
SetJumpTarget( pCTRDontBranch );
|
||||
|
||||
WriteExit(js.compilerPC + 4, 1);
|
||||
WriteExit(js.compilerPC + 4);
|
||||
}
|
||||
void JitArm::bcctrx(UGeckoInstruction inst)
|
||||
{
|
||||
@@ -276,7 +278,7 @@ void JitArm::bcctrx(UGeckoInstruction inst)
|
||||
WriteExitDestInR(rA);
|
||||
|
||||
SetJumpTarget(b);
|
||||
WriteExit(js.compilerPC + 4, 1);
|
||||
WriteExit(js.compilerPC + 4);
|
||||
}
|
||||
}
|
||||
void JitArm::bclrx(UGeckoInstruction inst)
|
||||
@@ -329,8 +331,11 @@ void JitArm::bclrx(UGeckoInstruction inst)
|
||||
// This below line can be used to prove that blr "eats flags" in practice.
|
||||
// This observation will let us do a lot of fun observations.
|
||||
#ifdef ACID_TEST
|
||||
// TODO: Not yet implemented
|
||||
// AND(32, M(&PowerPC::ppcState.cr), Imm32(~(0xFF000000)));
|
||||
if (inst.LK)
|
||||
{
|
||||
MOV(R14, 0);
|
||||
STRB(R14, R9, PPCSTATE_OFF(cr_fast[0]));
|
||||
}
|
||||
#endif
|
||||
|
||||
//MOV(32, R(EAX), M(&LR));
|
||||
@@ -350,5 +355,5 @@ void JitArm::bclrx(UGeckoInstruction inst)
|
||||
SetJumpTarget( pConditionDontBranch );
|
||||
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
|
||||
SetJumpTarget( pCTRDontBranch );
|
||||
WriteExit(js.compilerPC + 4, 1);
|
||||
WriteExit(js.compilerPC + 4);
|
||||
}
|
||||
|
||||
@@ -531,6 +531,6 @@ void JitArm::dcbst(UGeckoInstruction inst)
|
||||
void JitArm::icbi(UGeckoInstruction inst)
|
||||
{
|
||||
Default(inst);
|
||||
WriteExit(js.compilerPC + 4, 0);
|
||||
WriteExit(js.compilerPC + 4);
|
||||
}
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ void JitArm::mtmsr(UGeckoInstruction inst)
|
||||
gpr.Flush();
|
||||
fpr.Flush();
|
||||
|
||||
WriteExit(js.compilerPC + 4, 0);
|
||||
WriteExit(js.compilerPC + 4);
|
||||
}
|
||||
|
||||
void JitArm::mfmsr(UGeckoInstruction inst)
|
||||
|
||||
@@ -156,7 +156,8 @@ static ARMReg regEnsureInReg(RegInfo& RI, InstLoc I) {
|
||||
|
||||
static void regWriteExit(RegInfo& RI, InstLoc dest) {
|
||||
if (isImm(*dest)) {
|
||||
RI.Jit->WriteExit(RI.Build->GetImmValue(dest), RI.exitNumber++);
|
||||
RI.exitNumber++;
|
||||
RI.Jit->WriteExit(RI.Build->GetImmValue(dest));
|
||||
} else {
|
||||
RI.Jit->WriteExitDestInReg(regLocForInst(RI, dest));
|
||||
}
|
||||
@@ -281,7 +282,7 @@ static void regEmitCmp(RegInfo& RI, InstLoc I) {
|
||||
}
|
||||
}
|
||||
|
||||
static void DoWriteCode(IRBuilder* ibuild, JitArmIL* Jit) {
|
||||
static void DoWriteCode(IRBuilder* ibuild, JitArmIL* Jit, u32 exitAddress) {
|
||||
RegInfo RI(Jit, ibuild->getFirstInst(), ibuild->getNumInsts());
|
||||
RI.Build = ibuild;
|
||||
|
||||
@@ -733,10 +734,10 @@ static void DoWriteCode(IRBuilder* ibuild, JitArmIL* Jit) {
|
||||
}
|
||||
}
|
||||
|
||||
Jit->WriteExit(jit->js.curBlock->exitAddress[0], 0);
|
||||
Jit->WriteExit(exitAddress);
|
||||
Jit->BKPT(0x111);
|
||||
|
||||
}
|
||||
void JitArmIL::WriteCode() {
|
||||
DoWriteCode(&ibuild, this);
|
||||
void JitArmIL::WriteCode(u32 exitAddress) {
|
||||
DoWriteCode(&ibuild, this, exitAddress);
|
||||
}
|
||||
|
||||
@@ -117,13 +117,14 @@ void JitArmIL::WriteExceptionExit()
|
||||
MOVI2R(R14, (u32)asm_routines.testExceptions);
|
||||
B(R14);
|
||||
}
|
||||
void JitArmIL::WriteExit(u32 destination, int exit_num)
|
||||
void JitArmIL::WriteExit(u32 destination)
|
||||
{
|
||||
DoDownCount();
|
||||
//If nobody has taken care of this yet (this can be removed when all branches are done)
|
||||
JitBlock *b = js.curBlock;
|
||||
b->exitAddress[exit_num] = destination;
|
||||
b->exitPtrs[exit_num] = GetWritableCodePtr();
|
||||
JitBlock::LinkData linkData;
|
||||
linkData.exitAddress = destination;
|
||||
linkData.exitPtrs = GetWritableCodePtr();
|
||||
|
||||
// Link opportunity!
|
||||
int block = blocks.GetBlockNumberFromStartAddress(destination);
|
||||
@@ -131,7 +132,7 @@ void JitArmIL::WriteExit(u32 destination, int exit_num)
|
||||
{
|
||||
// It exists! Joy of joy!
|
||||
B(blocks.GetBlock(block)->checkedEntry);
|
||||
b->linkStatus[exit_num] = true;
|
||||
linkData.linkStatus = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -140,6 +141,8 @@ void JitArmIL::WriteExit(u32 destination, int exit_num)
|
||||
MOVI2R(R14, (u32)asm_routines.dispatcher);
|
||||
B(R14);
|
||||
}
|
||||
|
||||
b->linkData.push_back(linkData);
|
||||
}
|
||||
void JitArmIL::PrintDebug(UGeckoInstruction inst, u32 level)
|
||||
{
|
||||
@@ -347,12 +350,12 @@ const u8* JitArmIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB
|
||||
if (broken_block)
|
||||
{
|
||||
printf("Broken Block going to 0x%08x\n", nextPC);
|
||||
WriteExit(nextPC, 0);
|
||||
WriteExit(nextPC);
|
||||
}
|
||||
|
||||
// Perform actual code generation
|
||||
|
||||
WriteCode();
|
||||
WriteCode(nextPC);
|
||||
b->flags = js.block_flags;
|
||||
b->codeSize = (u32)(GetCodePtr() - normalEntry);
|
||||
b->originalSize = size;
|
||||
|
||||
@@ -64,8 +64,8 @@ public:
|
||||
void Run();
|
||||
void SingleStep();
|
||||
//
|
||||
void WriteCode();
|
||||
void WriteExit(u32 destination, int exit_num);
|
||||
void WriteCode(u32 exitAddress);
|
||||
void WriteExit(u32 destination);
|
||||
void WriteExitDestInReg(ARMReg Reg);
|
||||
void WriteRfiExitDestInR(ARMReg Reg);
|
||||
void WriteExceptionExit();
|
||||
|
||||
@@ -234,7 +234,7 @@ const u8 *Jitx86Base::BackPatch(u8 *codePtr, u32 emAddress, void *ctx_void)
|
||||
XEmitter emitter(start);
|
||||
const u8 *trampoline = trampolines.GetWriteTrampoline(info, registersInUse);
|
||||
emitter.CALL((void *)trampoline);
|
||||
emitter.NOP(codePtr + info.instructionSize - emitter.GetCodePtr());
|
||||
emitter.NOP((int)(codePtr + info.instructionSize - emitter.GetCodePtr()));
|
||||
return start;
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -35,8 +35,6 @@ op_agent_t agent;
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
#define INVALID_EXIT 0xFFFFFFFF
|
||||
|
||||
bool JitBaseBlockCache::IsFull() const
|
||||
{
|
||||
return GetNumBlocks() >= MAX_NUM_BLOCKS - 1;
|
||||
@@ -167,12 +165,6 @@ using namespace Gen;
|
||||
JitBlock &b = blocks[num_blocks];
|
||||
b.invalid = false;
|
||||
b.originalAddress = em_address;
|
||||
b.exitAddress[0] = INVALID_EXIT;
|
||||
b.exitAddress[1] = INVALID_EXIT;
|
||||
b.exitPtrs[0] = 0;
|
||||
b.exitPtrs[1] = 0;
|
||||
b.linkStatus[0] = false;
|
||||
b.linkStatus[1] = false;
|
||||
num_blocks++; //commit the current block
|
||||
return num_blocks - 1;
|
||||
}
|
||||
@@ -193,10 +185,9 @@ using namespace Gen;
|
||||
block_map[std::make_pair(pAddr + 4 * b.originalSize - 1, pAddr)] = block_num;
|
||||
if (block_link)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
for (const auto& e : b.linkData)
|
||||
{
|
||||
if (b.exitAddress[i] != INVALID_EXIT)
|
||||
links_to.insert(std::pair<u32, int>(b.exitAddress[i], block_num));
|
||||
links_to.insert(std::pair<u32, int>(e.exitAddress, block_num));
|
||||
}
|
||||
|
||||
LinkBlock(block_num);
|
||||
@@ -275,15 +266,15 @@ using namespace Gen;
|
||||
// This block is dead. Don't relink it.
|
||||
return;
|
||||
}
|
||||
for (int e = 0; e < 2; e++)
|
||||
for (auto& e : b.linkData)
|
||||
{
|
||||
if (b.exitAddress[e] != INVALID_EXIT && !b.linkStatus[e])
|
||||
if (!e.linkStatus)
|
||||
{
|
||||
int destinationBlock = GetBlockNumberFromStartAddress(b.exitAddress[e]);
|
||||
int destinationBlock = GetBlockNumberFromStartAddress(e.exitAddress);
|
||||
if (destinationBlock != -1)
|
||||
{
|
||||
WriteLinkBlock(b.exitPtrs[e], blocks[destinationBlock].checkedEntry);
|
||||
b.linkStatus[e] = true;
|
||||
WriteLinkBlock(e.exitPtrs, blocks[destinationBlock].checkedEntry);
|
||||
e.linkStatus = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -316,10 +307,10 @@ using namespace Gen;
|
||||
return;
|
||||
for (multimap<u32, int>::iterator iter = ppp.first; iter != ppp.second; ++iter) {
|
||||
JitBlock &sourceBlock = blocks[iter->second];
|
||||
for (int e = 0; e < 2; e++)
|
||||
for (auto& e : sourceBlock.linkData)
|
||||
{
|
||||
if (sourceBlock.exitAddress[e] == b.originalAddress)
|
||||
sourceBlock.linkStatus[e] = false;
|
||||
if (e.exitAddress == b.originalAddress)
|
||||
e.linkStatus = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,9 +35,6 @@ struct JitBlock
|
||||
const u8 *checkedEntry;
|
||||
const u8 *normalEntry;
|
||||
|
||||
u8 *exitPtrs[2]; // to be able to rewrite the exit jum
|
||||
u32 exitAddress[2]; // 0xFFFFFFFF == unknown
|
||||
|
||||
u32 originalAddress;
|
||||
u32 codeSize;
|
||||
u32 originalSize;
|
||||
@@ -45,7 +42,13 @@ struct JitBlock
|
||||
int flags;
|
||||
|
||||
bool invalid;
|
||||
bool linkStatus[2];
|
||||
|
||||
struct LinkData {
|
||||
u8 *exitPtrs; // to be able to rewrite the exit jum
|
||||
u32 exitAddress;
|
||||
bool linkStatus; // is it already linked?
|
||||
};
|
||||
std::vector<LinkData> linkData;
|
||||
|
||||
#ifdef _WIN32
|
||||
// we don't really need to save start and stop
|
||||
|
||||
@@ -323,7 +323,7 @@ void EmuCodeBlock::SafeWriteRegToReg(X64Reg reg_value, X64Reg reg_addr, int acce
|
||||
MOV(32, M(&PC), Imm32(jit->js.compilerPC)); // Helps external systems know which instruction triggered the write
|
||||
TEST(32, R(reg_addr), Imm32(mem_mask));
|
||||
FixupBranch fast = J_CC(CC_Z, true);
|
||||
bool noProlog = flags & SAFE_LOADSTORE_NO_PROLOG;
|
||||
bool noProlog = (0 != (flags & SAFE_LOADSTORE_NO_PROLOG));
|
||||
bool swap = !(flags & SAFE_LOADSTORE_NO_SWAP);
|
||||
ABI_PushRegistersAndAdjustStack(registersInUse, noProlog);
|
||||
switch (accessSize)
|
||||
|
||||
@@ -14,24 +14,15 @@
|
||||
#include "Interpreter/Interpreter_Tables.h"
|
||||
#include "JitInterface.h"
|
||||
|
||||
struct op_inf
|
||||
{
|
||||
const char *name;
|
||||
int count;
|
||||
bool operator < (const op_inf &o) const
|
||||
{
|
||||
return count > o.count;
|
||||
}
|
||||
};
|
||||
GekkoOPInfo *m_infoTable[64];
|
||||
GekkoOPInfo *m_infoTable4[1024];
|
||||
GekkoOPInfo *m_infoTable19[1024];
|
||||
GekkoOPInfo *m_infoTable31[1024];
|
||||
GekkoOPInfo *m_infoTable59[32];
|
||||
GekkoOPInfo *m_infoTable63[1024];
|
||||
GekkoOPInfo *m_infoTable[64];
|
||||
GekkoOPInfo *m_infoTable4[1024];
|
||||
GekkoOPInfo *m_infoTable19[1024];
|
||||
GekkoOPInfo *m_infoTable31[1024];
|
||||
GekkoOPInfo *m_infoTable59[32];
|
||||
GekkoOPInfo *m_infoTable63[1024];
|
||||
|
||||
GekkoOPInfo *m_allInstructions[512];
|
||||
int m_numInstructions;
|
||||
GekkoOPInfo *m_allInstructions[512];
|
||||
int m_numInstructions;
|
||||
|
||||
GekkoOPInfo *GetOpInfo(UGeckoInstruction _inst)
|
||||
{
|
||||
@@ -182,26 +173,34 @@ void CountInstruction(UGeckoInstruction _inst)
|
||||
{
|
||||
GekkoOPInfo *info = GetOpInfo(_inst);
|
||||
if (info)
|
||||
{
|
||||
info->runCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void PrintInstructionRunCounts()
|
||||
{
|
||||
std::vector<op_inf> temp;
|
||||
for (int i = 0; i < m_numInstructions; i++)
|
||||
typedef std::pair<const char*, u64> OpInfo;
|
||||
std::vector<OpInfo> temp;
|
||||
temp.reserve(m_numInstructions);
|
||||
for (int i = 0; i < m_numInstructions; ++i)
|
||||
{
|
||||
op_inf x;
|
||||
x.name = m_allInstructions[i]->opname;
|
||||
x.count = m_allInstructions[i]->runCount;
|
||||
temp.push_back(x);
|
||||
GekkoOPInfo *pInst = m_allInstructions[i];
|
||||
temp.emplace_back(pInst->opname, pInst->runCount);
|
||||
}
|
||||
std::sort(temp.begin(), temp.end());
|
||||
for (int i = 0; i < m_numInstructions; i++)
|
||||
std::sort(temp.begin(), temp.end(),
|
||||
[](const OpInfo &a, const OpInfo &b)
|
||||
{
|
||||
return a.second > b.second;
|
||||
});
|
||||
|
||||
for (auto &inst : temp)
|
||||
{
|
||||
if (temp[i].count == 0)
|
||||
if (inst.second == 0)
|
||||
break;
|
||||
DEBUG_LOG(POWERPC, "%s : %i", temp[i].name,temp[i].count);
|
||||
//PanicAlert("%s : %i", temp[i].name,temp[i].count);
|
||||
|
||||
DEBUG_LOG(POWERPC, "%s : %llu", inst.first, inst.second);
|
||||
//PanicAlert("%s : %llu", inst.first, inst.second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,20 +211,22 @@ void LogCompiledInstructions()
|
||||
File::IOFile f(StringFromFormat("%sinst_log%i.txt", File::GetUserPath(D_LOGS_IDX).c_str(), time), "w");
|
||||
for (int i = 0; i < m_numInstructions; i++)
|
||||
{
|
||||
if (m_allInstructions[i]->compileCount > 0)
|
||||
GekkoOPInfo *pInst = m_allInstructions[i];
|
||||
if (pInst->compileCount > 0)
|
||||
{
|
||||
fprintf(f.GetHandle(), "%s\t%i\t%" PRId64 "\t%08x\n", m_allInstructions[i]->opname,
|
||||
m_allInstructions[i]->compileCount, m_allInstructions[i]->runCount, m_allInstructions[i]->lastUse);
|
||||
fprintf(f.GetHandle(), "%s\t%i\t%" PRId64 "\t%08x\n", pInst->opname,
|
||||
pInst->compileCount, pInst->runCount, pInst->lastUse);
|
||||
}
|
||||
}
|
||||
|
||||
f.Open(StringFromFormat("%sinst_not%i.txt", File::GetUserPath(D_LOGS_IDX).c_str(), time), "w");
|
||||
for (int i = 0; i < m_numInstructions; i++)
|
||||
{
|
||||
if (m_allInstructions[i]->compileCount == 0)
|
||||
GekkoOPInfo *pInst = m_allInstructions[i];
|
||||
if (pInst->compileCount == 0)
|
||||
{
|
||||
fprintf(f.GetHandle(), "%s\t%i\t%" PRId64 "\n", m_allInstructions[i]->opname,
|
||||
m_allInstructions[i]->compileCount, m_allInstructions[i]->runCount);
|
||||
fprintf(f.GetHandle(), "%s\t%i\t%" PRId64 "\n", pInst->opname,
|
||||
pInst->compileCount, pInst->runCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -247,7 +247,7 @@ void CompressAndDumpState(CompressAndDumpState_args save_args)
|
||||
// Setting up the header
|
||||
StateHeader header;
|
||||
memcpy(header.gameID, SConfig::GetInstance().m_LocalCoreStartupParameter.GetUniqueID().c_str(), 6);
|
||||
header.size = g_use_compression ? buffer_size : 0;
|
||||
header.size = g_use_compression ? (u32)buffer_size : 0;
|
||||
header.time = Common::Timer::GetDoubleTime();
|
||||
|
||||
f.WriteArray(&header, 1);
|
||||
@@ -261,9 +261,13 @@ void CompressAndDumpState(CompressAndDumpState_args save_args)
|
||||
lzo_uint out_len = 0;
|
||||
|
||||
if ((i + IN_LEN) >= buffer_size)
|
||||
cur_len = buffer_size - i;
|
||||
{
|
||||
cur_len = (lzo_uint32)(buffer_size - i);
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_len = IN_LEN;
|
||||
}
|
||||
|
||||
if (lzo1x_1_compress(buffer_data + i, cur_len, out, &out_len, wrkmem) != LZO_E_OK)
|
||||
PanicAlertT("Internal LZO Error - compression failed");
|
||||
|
||||
@@ -282,10 +282,22 @@ JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetTitle(
|
||||
env->ReleaseStringUTFChars(jFile, File);
|
||||
return env->NewStringUTF(Name.c_str());
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersionString(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return env->NewStringUTF(scm_rev_str);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SupportsNEON(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return cpu_info.bNEON;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveScreenShot(JNIEnv *env, jobject obj)
|
||||
{
|
||||
Core::SaveScreenShot();
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetConfig(JNIEnv *env, jobject obj, jstring jFile, jstring jKey, jstring jValue, jstring jDefault)
|
||||
{
|
||||
IniFile ini;
|
||||
|
||||
@@ -154,12 +154,13 @@ Joystick::~Joystick()
|
||||
{
|
||||
// stop/destroy all effects
|
||||
SDL_HapticStopAll(m_haptic);
|
||||
std::list<EffectIDState>::iterator
|
||||
i = m_state_out.begin(),
|
||||
e = m_state_out.end();
|
||||
for ( ; i != e; ++i)
|
||||
if (i->id != -1)
|
||||
SDL_HapticDestroyEffect(m_haptic, i->id);
|
||||
for (auto &i : m_state_out)
|
||||
{
|
||||
if (i.id != -1)
|
||||
{
|
||||
SDL_HapticDestroyEffect(m_haptic, i.id);
|
||||
}
|
||||
}
|
||||
// close haptic first
|
||||
SDL_HapticClose(m_haptic);
|
||||
}
|
||||
@@ -210,7 +211,7 @@ void Joystick::ConstantEffect::SetState(ControlState state)
|
||||
}
|
||||
|
||||
const Sint16 old = m_effect.effect.constant.level;
|
||||
m_effect.effect.constant.level = state * 0x7FFF;
|
||||
m_effect.effect.constant.level = (Sint16)(state * 0x7FFF);
|
||||
if (old != m_effect.effect.constant.level)
|
||||
m_effect.changed = true;
|
||||
}
|
||||
@@ -228,7 +229,7 @@ void Joystick::RampEffect::SetState(ControlState state)
|
||||
}
|
||||
|
||||
const Sint16 old = m_effect.effect.ramp.start;
|
||||
m_effect.effect.ramp.start = state * 0x7FFF;
|
||||
m_effect.effect.ramp.start = (Sint16)(state * 0x7FFF);
|
||||
if (old != m_effect.effect.ramp.start)
|
||||
m_effect.changed = true;
|
||||
}
|
||||
@@ -247,7 +248,7 @@ void Joystick::SineEffect::SetState(ControlState state)
|
||||
|
||||
const Sint16 old = m_effect.effect.periodic.magnitude;
|
||||
m_effect.effect.periodic.period = 5;
|
||||
m_effect.effect.periodic.magnitude = state * 0x5000;
|
||||
m_effect.effect.periodic.magnitude = (Sint16)(state * 0x5000);
|
||||
m_effect.effect.periodic.attack_length = 0;
|
||||
m_effect.effect.periodic.fade_length = 500;
|
||||
|
||||
@@ -293,7 +294,7 @@ void Joystick::TriangleEffect::SetState(ControlState state)
|
||||
|
||||
const Sint16 old = m_effect.effect.periodic.magnitude;
|
||||
m_effect.effect.periodic.period = 5;
|
||||
m_effect.effect.periodic.magnitude = state * 0x5000;
|
||||
m_effect.effect.periodic.magnitude = (Sint16)(state * 0x5000);
|
||||
m_effect.effect.periodic.attack_length = 0;
|
||||
m_effect.effect.periodic.fade_length = 100;
|
||||
|
||||
@@ -313,34 +314,35 @@ bool Joystick::UpdateInput()
|
||||
bool Joystick::UpdateOutput()
|
||||
{
|
||||
#ifdef USE_SDL_HAPTIC
|
||||
std::list<EffectIDState>::iterator
|
||||
i = m_state_out.begin(),
|
||||
e = m_state_out.end();
|
||||
for ( ; i != e; ++i)
|
||||
for (auto &i : m_state_out)
|
||||
{
|
||||
if (i->changed) // if SetState was called on this output
|
||||
if (i.changed) // if SetState was called on this output
|
||||
{
|
||||
if (-1 == i->id) // effect isn't currently uploaded
|
||||
if (-1 == i.id) // effect isn't currently uploaded
|
||||
{
|
||||
if (i->effect.type) // if outputstate is >0 this would be true
|
||||
if ((i->id = SDL_HapticNewEffect( m_haptic, &i->effect )) > -1) // upload the effect
|
||||
SDL_HapticRunEffect(m_haptic, i->id, 1); // run the effect
|
||||
if (i.effect.type) // if outputstate is >0 this would be true
|
||||
{
|
||||
if ((i.id = SDL_HapticNewEffect(m_haptic, &i.effect)) > -1) // upload the effect
|
||||
{
|
||||
SDL_HapticRunEffect(m_haptic, i.id, 1); // run the effect
|
||||
}
|
||||
}
|
||||
}
|
||||
else // effect is already uploaded
|
||||
{
|
||||
if (i->effect.type) // if ouputstate >0
|
||||
if (i.effect.type) // if ouputstate >0
|
||||
{
|
||||
SDL_HapticUpdateEffect(m_haptic, i->id, &i->effect); // update the effect
|
||||
SDL_HapticUpdateEffect(m_haptic, i.id, &i.effect); // update the effect
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_HapticStopEffect(m_haptic, i->id); // else, stop and remove the effect
|
||||
SDL_HapticDestroyEffect(m_haptic, i->id);
|
||||
i->id = -1; // mark it as not uploaded
|
||||
SDL_HapticStopEffect(m_haptic, i.id); // else, stop and remove the effect
|
||||
SDL_HapticDestroyEffect(m_haptic, i.id);
|
||||
i.id = -1; // mark it as not uploaded
|
||||
}
|
||||
}
|
||||
|
||||
i->changed = false;
|
||||
i.changed = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -5,138 +5,12 @@
|
||||
#include "D3DBase.h"
|
||||
#include "D3DTexture.h"
|
||||
|
||||
#include <atlbase.h>
|
||||
#include <wincodec.h>
|
||||
#include <wincodecsdk.h>
|
||||
#pragma comment(lib, "WindowsCodecs.lib")
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
|
||||
HRESULT TextureToPng(D3D11_MAPPED_SUBRESOURCE &map, LPCWSTR wzFilename, int width, int height, bool saveAlpha)
|
||||
{
|
||||
IWICImagingFactory *piFactory = NULL;
|
||||
IWICBitmapEncoder *piEncoder = NULL;
|
||||
IWICBitmapFrameEncode *piBitmapFrame = NULL;
|
||||
IPropertyBag2 *pPropertybag = NULL;
|
||||
|
||||
IWICStream *piStream = NULL;
|
||||
|
||||
HRESULT hr = CoCreateInstance(
|
||||
CLSID_WICImagingFactory,
|
||||
NULL,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
IID_IWICImagingFactory,
|
||||
(LPVOID*)&piFactory);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = piFactory->CreateStream(&piStream);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = piStream->InitializeFromFilename(wzFilename, GENERIC_WRITE);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = piFactory->CreateEncoder(GUID_ContainerFormatPng, NULL, &piEncoder);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = piEncoder->Initialize(piStream, WICBitmapEncoderNoCache);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = piEncoder->CreateNewFrame(&piBitmapFrame, &pPropertybag);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = piBitmapFrame->Initialize(pPropertybag);
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = piBitmapFrame->SetSize(width, height);
|
||||
}
|
||||
|
||||
WICPixelFormatGUID formatGUID = GUID_WICPixelFormat32bppBGRA;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = piBitmapFrame->SetPixelFormat(&formatGUID);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// We're expecting to write out 32bppBGRA. Fail if the encoder cannot do it.
|
||||
hr = IsEqualGUID(formatGUID, GUID_WICPixelFormat32bppBGRA) ? S_OK : E_FAIL;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (map.pData != NULL)
|
||||
{
|
||||
for (int y = 0; y < height; ++y)
|
||||
{
|
||||
u8* ptr = (u8*)map.pData + y * map.RowPitch;
|
||||
for (unsigned int x = 0; x < map.RowPitch/4; ++x)
|
||||
{
|
||||
u8 r = ptr[0];
|
||||
u8 g = ptr[1];
|
||||
u8 b = ptr[2];
|
||||
ptr[0] = b;
|
||||
ptr[1] = g;
|
||||
ptr[2] = r;
|
||||
if (!saveAlpha)
|
||||
ptr[3] = 0xff;
|
||||
|
||||
|
||||
ptr += 4;
|
||||
}
|
||||
}
|
||||
hr = piBitmapFrame->WritePixels(height, map.RowPitch, height * map.RowPitch, (BYTE*)map.pData);
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = piBitmapFrame->Commit();
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = piEncoder->Commit();
|
||||
}
|
||||
|
||||
if (piFactory)
|
||||
piFactory->Release();
|
||||
|
||||
if (piBitmapFrame)
|
||||
piBitmapFrame->Release();
|
||||
|
||||
if (piEncoder)
|
||||
piEncoder->Release();
|
||||
|
||||
if (piStream)
|
||||
piStream->Release();
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage)
|
||||
{
|
||||
if (usage == D3D11_USAGE_DYNAMIC || usage == D3D11_USAGE_STAGING)
|
||||
|
||||
@@ -11,7 +11,6 @@ namespace DX11
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
HRESULT TextureToPng(D3D11_MAPPED_SUBRESOURCE& map, LPCWSTR wzFilename, int width, int height, bool saveAlpha = true);
|
||||
void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage);
|
||||
}
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ void FramebufferManager::GetTargetSize(unsigned int *width, unsigned int *height
|
||||
}
|
||||
|
||||
void XFBSource::Draw(const MathUtil::Rectangle<float> &sourcerc,
|
||||
const MathUtil::Rectangle<float> &drawrc, int width, int height) const
|
||||
const MathUtil::Rectangle<float> &drawrc) const
|
||||
{
|
||||
D3D::drawShadedTexSubQuad(tex->GetSRV(), &sourcerc,
|
||||
texWidth, texHeight, &drawrc, PixelShaderCache::GetColorCopyProgram(false),
|
||||
|
||||
@@ -51,7 +51,7 @@ struct XFBSource : public XFBSourceBase
|
||||
~XFBSource() { tex->Release(); }
|
||||
|
||||
void Draw(const MathUtil::Rectangle<float> &sourcerc,
|
||||
const MathUtil::Rectangle<float> &drawrc, int width, int height) const;
|
||||
const MathUtil::Rectangle<float> &drawrc) const;
|
||||
void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
|
||||
void CopyEFB(float Gamma);
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "FPSCounter.h"
|
||||
#include "ConfigManager.h"
|
||||
#include <strsafe.h>
|
||||
#include "ImageWrite.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
@@ -693,11 +694,12 @@ bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ_WRITE, 0, &map);
|
||||
|
||||
// ready to be saved
|
||||
HRESULT hr = D3D::TextureToPng(map, UTF8ToUTF16(filename.c_str()).c_str(), rc.GetWidth(), rc.GetHeight(), false);
|
||||
bool saved_png = TextureToPng((u8*)map.pData, map.RowPitch, filename, rc.GetWidth(), rc.GetHeight(), false);
|
||||
|
||||
D3D::context->Unmap(s_screenshot_texture, 0);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
|
||||
if (saved_png)
|
||||
{
|
||||
OSD::AddMessage(StringFromFormat("Saved %i x %i %s", rc.GetWidth(),
|
||||
rc.GetHeight(), filename.c_str()));
|
||||
@@ -707,7 +709,7 @@ bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle
|
||||
OSD::AddMessage(StringFromFormat("Error saving %s", filename.c_str()));
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
return saved_png;
|
||||
}
|
||||
|
||||
void formatBufferDump(const u8* in, u8* out, int w, int h, int p)
|
||||
@@ -830,7 +832,7 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbHeight,const EFBRectangle& r
|
||||
//drawRc.right *= hScale;
|
||||
}
|
||||
|
||||
xfbSource->Draw(sourceRc, drawRc, 0, 0);
|
||||
xfbSource->Draw(sourceRc, drawRc);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -14,12 +14,13 @@
|
||||
#include "PSTextureEncoder.h"
|
||||
#include "HW/Memmap.h"
|
||||
#include "VideoConfig.h"
|
||||
#include "ImageWrite.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
static TextureEncoder* g_encoder = NULL;
|
||||
const size_t MAX_COPY_BUFFERS = 25;
|
||||
const size_t MAX_COPY_BUFFERS = 32;
|
||||
ID3D11Buffer* efbcopycbuf[MAX_COPY_BUFFERS] = { 0 };
|
||||
|
||||
TextureCache::TCacheEntry::~TCacheEntry()
|
||||
@@ -32,7 +33,7 @@ void TextureCache::TCacheEntry::Bind(unsigned int stage)
|
||||
D3D::context->PSSetShaderResources(stage, 1, &texture->GetSRV());
|
||||
}
|
||||
|
||||
bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
|
||||
bool TextureCache::TCacheEntry::Save(const std::string filename, unsigned int level)
|
||||
{
|
||||
// TODO: Somehow implement this (D3DX11 doesn't support dumping individual LODs)
|
||||
static bool warn_once = true;
|
||||
@@ -54,6 +55,8 @@ bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
|
||||
|
||||
HRESULT hr = D3D::device->CreateTexture2D(&desc, NULL, &pNewTexture);
|
||||
|
||||
bool saved_png = false;
|
||||
|
||||
if (SUCCEEDED(hr) && pNewTexture)
|
||||
{
|
||||
D3D::context->CopyResource(pNewTexture, pSurface);
|
||||
@@ -62,13 +65,13 @@ bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
|
||||
HRESULT hr = D3D::context->Map(pNewTexture, 0, D3D11_MAP_READ_WRITE, 0, &map);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = D3D::TextureToPng(map, UTF8ToUTF16(filename).c_str(), desc.Width, desc.Height);
|
||||
saved_png = TextureToPng((u8*)map.pData, map.RowPitch, filename, desc.Width, desc.Height);
|
||||
D3D::context->Unmap(pNewTexture, 0);
|
||||
}
|
||||
SAFE_RELEASE(pNewTexture);
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
return saved_png;
|
||||
}
|
||||
|
||||
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
|
||||
|
||||
@@ -36,7 +36,7 @@ private:
|
||||
const float *colmat);
|
||||
|
||||
void Bind(unsigned int stage);
|
||||
bool Save(const char filename[], unsigned int level);
|
||||
bool Save(const std::string filename, unsigned int level);
|
||||
};
|
||||
|
||||
TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height,
|
||||
|
||||
@@ -66,15 +66,6 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
|
||||
// alpha channel should be ignored if the EFB does not have one.
|
||||
|
||||
// Create EFB target.
|
||||
u32 depthType;
|
||||
if (DriverDetails::HasBug(DriverDetails::BUG_ISTEGRA))
|
||||
{
|
||||
depthType = GL_DEPTH_COMPONENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
depthType = GL_DEPTH_COMPONENT24;
|
||||
}
|
||||
glGenFramebuffers(1, &m_efbFramebuffer);
|
||||
glActiveTexture(GL_TEXTURE0 + 9);
|
||||
|
||||
@@ -94,7 +85,7 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
|
||||
|
||||
glBindTexture(getFbType(), m_efbDepth);
|
||||
glTexParameteri(getFbType(), GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(getFbType(), 0, depthType, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
|
||||
glTexImage2D(getFbType(), 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
|
||||
|
||||
glBindTexture(getFbType(), m_resolvedColorTexture);
|
||||
glTexParameteri(getFbType(), GL_TEXTURE_MAX_LEVEL, 0);
|
||||
@@ -159,7 +150,7 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
|
||||
|
||||
glBindTexture(getFbType(), m_resolvedDepthTexture);
|
||||
glTexParameteri(getFbType(), GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(getFbType(), 0, depthType, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
|
||||
glTexImage2D(getFbType(), 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
|
||||
|
||||
// Bind resolved textures to resolved framebuffer.
|
||||
|
||||
@@ -235,13 +226,8 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
|
||||
" ocol0 = float4(dst6) / 63.f;\n"
|
||||
"}";
|
||||
|
||||
if(g_ogl_config.eSupportedGLSLVersion != GLSLES2)
|
||||
{
|
||||
// HACK: This shaders aren't glsles2 compatible as glsles2 don't support bit operations
|
||||
// it could be workaround by floor + frac + tons off additions, but I think it isn't worth
|
||||
ProgramShaderCache::CompileShader(m_pixel_format_shaders[0], vs, ps_rgb8_to_rgba6);
|
||||
ProgramShaderCache::CompileShader(m_pixel_format_shaders[1], vs, ps_rgba6_to_rgb8);
|
||||
}
|
||||
ProgramShaderCache::CompileShader(m_pixel_format_shaders[0], vs, ps_rgb8_to_rgba6);
|
||||
ProgramShaderCache::CompileShader(m_pixel_format_shaders[1], vs, ps_rgba6_to_rgb8);
|
||||
}
|
||||
|
||||
FramebufferManager::~FramebufferManager()
|
||||
@@ -372,19 +358,6 @@ GLuint FramebufferManager::ResolveAndGetDepthTarget(const EFBRectangle &source_r
|
||||
|
||||
void FramebufferManager::ReinterpretPixelData(unsigned int convtype)
|
||||
{
|
||||
if(g_ogl_config.eSupportedGLSLVersion == GLSLES2) {
|
||||
// This feature isn't supported by glsles2
|
||||
|
||||
// TODO: move this to InitBackendInfo
|
||||
// We have to disable both the active and the stored config. Else we
|
||||
// would either
|
||||
// show this line per format change in one frame or
|
||||
// once per frame.
|
||||
OSD::AddMessage("Format Change Emulation isn't supported by your GPU.", 10000);
|
||||
g_ActiveConfig.bEFBEmulateFormatChanges = false;
|
||||
g_Config.bEFBEmulateFormatChanges = false;
|
||||
return;
|
||||
}
|
||||
g_renderer->ResetAPIState();
|
||||
|
||||
GLuint src_texture = 0;
|
||||
@@ -433,7 +406,7 @@ XFBSource::~XFBSource()
|
||||
|
||||
|
||||
void XFBSource::Draw(const MathUtil::Rectangle<float> &sourcerc,
|
||||
const MathUtil::Rectangle<float> &drawrc, int width, int height) const
|
||||
const MathUtil::Rectangle<float> &drawrc) const
|
||||
{
|
||||
// Texture map xfbSource->texture onto the main buffer
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
|
||||
|
||||
@@ -52,7 +52,7 @@ struct XFBSource : public XFBSourceBase
|
||||
void CopyEFB(float Gamma) override;
|
||||
void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override;
|
||||
void Draw(const MathUtil::Rectangle<float> &sourcerc,
|
||||
const MathUtil::Rectangle<float> &drawrc, int width, int height) const override;
|
||||
const MathUtil::Rectangle<float> &drawrc) const override;
|
||||
|
||||
const GLuint texture;
|
||||
};
|
||||
|
||||
@@ -72,67 +72,42 @@ namespace GLFunc
|
||||
self = dlopen(NULL, RTLD_LAZY);
|
||||
|
||||
LoadFunction("glUnmapBuffer", (void**)&glUnmapBuffer);
|
||||
LoadFunction("glBeginQuery", (void**)&glBeginQuery);
|
||||
LoadFunction("glEndQuery", (void**)&glEndQuery);
|
||||
LoadFunction("glGetQueryObjectuiv", (void**)&glGetQueryObjectuiv);
|
||||
LoadFunction("glDeleteQueries", (void**)&glDeleteQueries);
|
||||
LoadFunction("glGenQueries", (void**)&glGenQueries);
|
||||
|
||||
if (DriverDetails::HasBug(DriverDetails::BUG_ISTEGRA))
|
||||
{
|
||||
LoadFunction("glBeginQueryEXT", (void**)&glBeginQuery);
|
||||
LoadFunction("glEndQueryEXT", (void**)&glEndQuery);
|
||||
LoadFunction("glGetQueryObjectuivEXT", (void**)&glGetQueryObjectuiv);
|
||||
LoadFunction("glDeleteQueriesEXT", (void**)&glDeleteQueries);
|
||||
LoadFunction("glGenQueriesEXT", (void**)&glGenQueries);
|
||||
LoadFunction("glMapBufferRange", (void**)&glMapBufferRange);
|
||||
LoadFunction("glBindBufferRange", (void**)&glBindBufferRange);
|
||||
LoadFunction("glBlitFramebuffer", (void**)&glBlitFramebuffer);
|
||||
|
||||
LoadFunction("glMapBufferRangeNV", (void**)&glMapBufferRange);
|
||||
LoadFunction("glBindBufferRangeNV", (void**)&glBindBufferRange);
|
||||
LoadFunction("glBlitFramebufferNV", (void**)&glBlitFramebuffer);
|
||||
LoadFunction("glGenVertexArrays", (void**)&glGenVertexArrays);
|
||||
LoadFunction("glDeleteVertexArrays", (void**)&glDeleteVertexArrays);
|
||||
LoadFunction("glBindVertexArray", (void**)&glBindVertexArray);
|
||||
|
||||
LoadFunction("glGenVertexArraysOES", (void**)&glGenVertexArrays);
|
||||
LoadFunction("glDeleteVertexArraysOES", (void**)&glDeleteVertexArrays);
|
||||
LoadFunction("glBindVertexArrayOES", (void**)&glBindVertexArray);
|
||||
LoadFunction("glClientWaitSync", (void**)&glClientWaitSync);
|
||||
LoadFunction("glDeleteSync", (void**)&glDeleteSync);
|
||||
LoadFunction("glFenceSync", (void**)&glFenceSync);
|
||||
|
||||
LoadFunction("glRenderbufferStorageMultisampleNV", (void**)&glRenderbufferStorageMultisample);
|
||||
LoadFunction("glSamplerParameterf", (void**)&glSamplerParameterf);
|
||||
LoadFunction("glSamplerParameteri", (void**)&glSamplerParameteri);
|
||||
LoadFunction("glSamplerParameterfv", (void**)&glSamplerParameterfv);
|
||||
LoadFunction("glBindSampler", (void**)&glBindSampler);
|
||||
LoadFunction("glDeleteSamplers", (void**)&glDeleteSamplers);
|
||||
LoadFunction("glGenSamplers", (void**)&glGenSamplers);
|
||||
|
||||
LoadFunction("glGetUniformBlockIndexNV", (void**)&glGetUniformBlockIndex);
|
||||
LoadFunction("glUniformBlockBindingNV", (void**)&glUniformBlockBinding);
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadFunction("glBeginQuery", (void**)&glBeginQuery);
|
||||
LoadFunction("glEndQuery", (void**)&glEndQuery);
|
||||
LoadFunction("glGetQueryObjectuiv", (void**)&glGetQueryObjectuiv);
|
||||
LoadFunction("glDeleteQueries", (void**)&glDeleteQueries);
|
||||
LoadFunction("glGenQueries", (void**)&glGenQueries);
|
||||
LoadFunction("glGetProgramBinary", (void**)&glGetProgramBinary);
|
||||
LoadFunction("glProgramBinary", (void**)&glProgramBinary);
|
||||
LoadFunction("glProgramParameteri", (void**)&glProgramParameteri);
|
||||
|
||||
LoadFunction("glMapBufferRange", (void**)&glMapBufferRange);
|
||||
LoadFunction("glBindBufferRange", (void**)&glBindBufferRange);
|
||||
LoadFunction("glBlitFramebuffer", (void**)&glBlitFramebuffer);
|
||||
LoadFunction("glDrawRangeElements", (void**)&glDrawRangeElements);
|
||||
|
||||
LoadFunction("glGenVertexArrays", (void**)&glGenVertexArrays);
|
||||
LoadFunction("glDeleteVertexArrays", (void**)&glDeleteVertexArrays);
|
||||
LoadFunction("glBindVertexArray", (void**)&glBindVertexArray);
|
||||
LoadFunction("glRenderbufferStorageMultisample", (void**)&glRenderbufferStorageMultisample);
|
||||
|
||||
LoadFunction("glClientWaitSync", (void**)&glClientWaitSync);
|
||||
LoadFunction("glDeleteSync", (void**)&glDeleteSync);
|
||||
LoadFunction("glFenceSync", (void**)&glFenceSync);
|
||||
LoadFunction("glGetUniformBlockIndex", (void**)&glGetUniformBlockIndex);
|
||||
LoadFunction("glUniformBlockBinding", (void**)&glUniformBlockBinding);
|
||||
|
||||
LoadFunction("glSamplerParameterf", (void**)&glSamplerParameterf);
|
||||
LoadFunction("glSamplerParameteri", (void**)&glSamplerParameteri);
|
||||
LoadFunction("glSamplerParameterfv", (void**)&glSamplerParameterfv);
|
||||
LoadFunction("glBindSampler", (void**)&glBindSampler);
|
||||
LoadFunction("glDeleteSamplers", (void**)&glDeleteSamplers);
|
||||
LoadFunction("glGenSamplers", (void**)&glGenSamplers);
|
||||
|
||||
LoadFunction("glGetProgramBinary", (void**)&glGetProgramBinary);
|
||||
LoadFunction("glProgramBinary", (void**)&glProgramBinary);
|
||||
LoadFunction("glProgramParameteri", (void**)&glProgramParameteri);
|
||||
|
||||
LoadFunction("glDrawRangeElements", (void**)&glDrawRangeElements);
|
||||
|
||||
LoadFunction("glRenderbufferStorageMultisample", (void**)&glRenderbufferStorageMultisample);
|
||||
|
||||
LoadFunction("glGetUniformBlockIndex", (void**)&glGetUniformBlockIndex);
|
||||
LoadFunction("glUniformBlockBinding", (void**)&glUniformBlockBinding);
|
||||
|
||||
}
|
||||
dlclose(self);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -571,12 +571,12 @@ void ProgramShaderCache::CreateHeader ( void )
|
||||
"%s\n" // ubo
|
||||
"%s\n" // early-z
|
||||
|
||||
// Precision defines for GLSLES2/3
|
||||
// Precision defines for GLSLES3
|
||||
"%s\n"
|
||||
|
||||
"\n"// A few required defines and ones that will make our lives a lot easier
|
||||
"#define ATTRIN %s\n"
|
||||
"#define ATTROUT %s\n"
|
||||
"#define ATTRIN in\n"
|
||||
"#define ATTROUT out\n"
|
||||
"#define VARYIN %s\n"
|
||||
"#define VARYOUT %s\n"
|
||||
|
||||
@@ -594,40 +594,18 @@ void ProgramShaderCache::CreateHeader ( void )
|
||||
"%s\n"
|
||||
"%s\n"
|
||||
|
||||
// GLSLES2 hacks
|
||||
"%s\n"
|
||||
"%s\n"
|
||||
"%s\n"
|
||||
"%s\n"
|
||||
"%s\n"
|
||||
"%s\n"
|
||||
"%s\n"
|
||||
"#define COLOROUT(name) %s\n"
|
||||
|
||||
|
||||
, v==GLSLES2 ? "" : v==GLSLES3 ? "#version 300 es" : v==GLSL_130 ? "#version 130" : v==GLSL_140 ? "#version 140" : "#version 150"
|
||||
, v==GLSLES3 ? "#version 300 es" : v==GLSL_130 ? "#version 130" : v==GLSL_140 ? "#version 140" : "#version 150"
|
||||
, g_ActiveConfig.backend_info.bSupportsGLSLUBO && v<GLSL_140 ? "#extension GL_ARB_uniform_buffer_object : enable" : ""
|
||||
, g_ActiveConfig.backend_info.bSupportsEarlyZ ? "#extension GL_ARB_shader_image_load_store : enable" : ""
|
||||
|
||||
, (v==GLSLES3 || v==GLSLES2) ? "precision highp float;" : ""
|
||||
, v==GLSLES3 ? "precision highp float;" : ""
|
||||
|
||||
, v==GLSLES2 ? "attribute" : "in"
|
||||
, v==GLSLES2 ? "attribute" : "out"
|
||||
, v==GLSLES2 ? "varying" : DriverDetails::HasBug(DriverDetails::BUG_BROKENCENTROID) ? "in" : "centroid in"
|
||||
, v==GLSLES2 ? "varying" : DriverDetails::HasBug(DriverDetails::BUG_BROKENCENTROID) ? "out" : "centroid out"
|
||||
, DriverDetails::HasBug(DriverDetails::BUG_BROKENCENTROID) ? "in" : "centroid in"
|
||||
, DriverDetails::HasBug(DriverDetails::BUG_BROKENCENTROID) ? "out" : "centroid out"
|
||||
|
||||
, v==GLSLES2 ? "#define texture2DRect texture2D" : v==GLSLES3 ? "" : v<=GLSL_130 ? "#extension GL_ARB_texture_rectangle : enable" : "#define texture2DRect texture"
|
||||
, v==GLSLES3 ? "" : v<=GLSL_130 ? "#extension GL_ARB_texture_rectangle : enable" : "#define texture2DRect texture"
|
||||
, v==GLSLES3 ? "#define texture2DRect(samp, uv) texelFetch(samp, ivec2(floor(uv)), 0)" : ""
|
||||
, (v==GLSLES3 || v==GLSLES2) ? "#define sampler2DRect sampler2D" : ""
|
||||
|
||||
, v==GLSLES2 ? "#define texture texture2D" : ""
|
||||
, v==GLSLES2 ? "#define round(x) floor((x)+0.5)" : ""
|
||||
, v==GLSLES2 ? "#define out " : ""
|
||||
, v==GLSLES2 ? "#define ocol0 gl_FragColor" : ""
|
||||
, v==GLSLES2 ? "#define ocol1 gl_FragColor" : ""
|
||||
, DriverDetails::HasBug(DriverDetails::BUG_ISTEGRA) ? "#extension GL_NV_uniform_buffer_object : enable" : ""
|
||||
, DriverDetails::HasBug(DriverDetails::BUG_ISTEGRA) ? "#extension GL_NV_fragdepth : enable" : ""
|
||||
, v==GLSLES2 ? "" : "out vec4 name;"
|
||||
, v==GLSLES3 ? "#define sampler2DRect sampler2D" : ""
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ RasterFont::RasterFont()
|
||||
for(u32 y=0; y<char_height; y++) {
|
||||
for(u32 c=0; c<char_count; c++) {
|
||||
for(u32 x=0; x<char_width; x++) {
|
||||
bool pixel = rasters[c][y] & (1<<(char_width-x-1));
|
||||
bool pixel = (0 != (rasters[c][y] & (1<<(char_width-x-1))));
|
||||
texture_data[char_width*char_count*y+char_width*c+x] = pixel ? -1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,10 +63,6 @@
|
||||
#include "AVIDump.h"
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
#include <wx/image.h>
|
||||
#endif
|
||||
|
||||
// glew1.8 doesn't define KHR_debug
|
||||
#ifndef GL_DEBUG_OUTPUT
|
||||
#define GL_DEBUG_OUTPUT 0x92E0
|
||||
@@ -78,18 +74,6 @@ void VideoConfig::UpdateProjectionHack()
|
||||
::UpdateProjectionHack(g_Config.iPhackvalue, g_Config.sPhackvalue);
|
||||
}
|
||||
|
||||
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
// Screenshot thread struct
|
||||
typedef struct
|
||||
{
|
||||
int W, H;
|
||||
std::string filename;
|
||||
wxImage *img;
|
||||
} ScrStrct;
|
||||
#endif
|
||||
|
||||
|
||||
int OSDInternalW, OSDInternalH;
|
||||
|
||||
namespace OGL
|
||||
@@ -387,10 +371,7 @@ Renderer::Renderer()
|
||||
g_ogl_config.bSupportSampleShading = false;
|
||||
g_ogl_config.bSupportOGL31 = false;
|
||||
g_ogl_config.bSupportViewportFloat = false;
|
||||
if (DriverDetails::HasBug(DriverDetails::BUG_ISTEGRA) || DriverDetails::HasBug(DriverDetails::BUG_ISPOWERVR))
|
||||
g_ogl_config.eSupportedGLSLVersion = GLSLES2;
|
||||
else
|
||||
g_ogl_config.eSupportedGLSLVersion = GLSLES3;
|
||||
g_ogl_config.eSupportedGLSLVersion = GLSLES3;
|
||||
#else
|
||||
#ifdef __APPLE__
|
||||
glewExperimental = 1;
|
||||
@@ -485,19 +466,23 @@ Renderer::Renderer()
|
||||
|
||||
}
|
||||
|
||||
g_Config.backend_info.bSupportsDualSourceBlend = GLEW_ARB_blend_func_extended;
|
||||
g_Config.backend_info.bSupportsGLSLUBO = GLEW_ARB_uniform_buffer_object;
|
||||
g_Config.backend_info.bSupportsPrimitiveRestart = GLEW_VERSION_3_1 || GLEW_NV_primitive_restart;
|
||||
g_Config.backend_info.bSupportsEarlyZ = GLEW_ARB_shader_image_load_store;
|
||||
#define TO_BOOL(c) (0 != (c))
|
||||
|
||||
g_ogl_config.bSupportsGLSLCache = GLEW_ARB_get_program_binary;
|
||||
g_ogl_config.bSupportsGLPinnedMemory = GLEW_AMD_pinned_memory;
|
||||
g_ogl_config.bSupportsGLSync = GLEW_ARB_sync;
|
||||
g_ogl_config.bSupportsGLBaseVertex = GLEW_ARB_draw_elements_base_vertex;
|
||||
g_ogl_config.bSupportCoverageMSAA = GLEW_NV_framebuffer_multisample_coverage;
|
||||
g_ogl_config.bSupportSampleShading = GLEW_ARB_sample_shading;
|
||||
g_ogl_config.bSupportOGL31 = GLEW_VERSION_3_1;
|
||||
g_ogl_config.bSupportViewportFloat = GLEW_ARB_viewport_array;
|
||||
g_Config.backend_info.bSupportsDualSourceBlend = TO_BOOL(GLEW_ARB_blend_func_extended);
|
||||
g_Config.backend_info.bSupportsGLSLUBO = TO_BOOL(GLEW_ARB_uniform_buffer_object);
|
||||
g_Config.backend_info.bSupportsPrimitiveRestart = TO_BOOL(GLEW_VERSION_3_1) || TO_BOOL(GLEW_NV_primitive_restart);
|
||||
g_Config.backend_info.bSupportsEarlyZ = TO_BOOL(GLEW_ARB_shader_image_load_store);
|
||||
|
||||
g_ogl_config.bSupportsGLSLCache = TO_BOOL(GLEW_ARB_get_program_binary);
|
||||
g_ogl_config.bSupportsGLPinnedMemory = TO_BOOL(GLEW_AMD_pinned_memory);
|
||||
g_ogl_config.bSupportsGLSync = TO_BOOL(GLEW_ARB_sync);
|
||||
g_ogl_config.bSupportsGLBaseVertex = TO_BOOL(GLEW_ARB_draw_elements_base_vertex);
|
||||
g_ogl_config.bSupportCoverageMSAA = TO_BOOL(GLEW_NV_framebuffer_multisample_coverage);
|
||||
g_ogl_config.bSupportSampleShading = TO_BOOL(GLEW_ARB_sample_shading);
|
||||
g_ogl_config.bSupportOGL31 = TO_BOOL(GLEW_VERSION_3_1);
|
||||
g_ogl_config.bSupportViewportFloat = TO_BOOL(GLEW_ARB_viewport_array);
|
||||
|
||||
#undef TO_BOOL
|
||||
|
||||
if(strstr(g_ogl_config.glsl_version, "1.00") || strstr(g_ogl_config.glsl_version, "1.10") || strstr(g_ogl_config.glsl_version, "1.20"))
|
||||
{
|
||||
@@ -1391,7 +1376,7 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbHeight,const EFBRectangle& r
|
||||
sourceRc.top = xfbSource->sourceRc.top;
|
||||
sourceRc.bottom = xfbSource->sourceRc.bottom;
|
||||
|
||||
xfbSource->Draw(sourceRc, drawRc, 0, 0);
|
||||
xfbSource->Draw(sourceRc, drawRc);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1639,7 +1624,7 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbHeight,const EFBRectangle& r
|
||||
|
||||
// For testing zbuffer targets.
|
||||
// Renderer::SetZBufferRender();
|
||||
// SaveTexture("tex.tga", GL_TEXTURE_2D, s_FakeZTarget,
|
||||
// SaveTexture("tex.png", GL_TEXTURE_2D, s_FakeZTarget,
|
||||
// GetTargetWidth(), GetTargetHeight());
|
||||
Core::Callback_VideoCopiedToXFB(XFBWrited || (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB));
|
||||
XFBWrited = false;
|
||||
@@ -1800,69 +1785,21 @@ void Renderer::SetInterlacingMode()
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Renderer::FlipImageData(u8 *data, int w, int h)
|
||||
void Renderer::FlipImageData(u8 *data, int w, int h, int pixel_width)
|
||||
{
|
||||
// Flip image upside down. Damn OpenGL.
|
||||
for (int y = 0; y < h / 2; y++)
|
||||
for (int y = 0; y < h / 2; ++y)
|
||||
{
|
||||
for(int x = 0; x < w; x++)
|
||||
for(int x = 0; x < w; ++x)
|
||||
{
|
||||
std::swap(data[(y * w + x) * 3], data[((h - 1 - y) * w + x) * 3]);
|
||||
std::swap(data[(y * w + x) * 3 + 1], data[((h - 1 - y) * w + x) * 3 + 1]);
|
||||
std::swap(data[(y * w + x) * 3 + 2], data[((h - 1 - y) * w + x) * 3 + 2]);
|
||||
for (auto delta = 0; delta < pixel_width; ++delta)
|
||||
std::swap(data[(y * w + x) * pixel_width + delta], data[((h - 1 - y) * w + x) * pixel_width + delta]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO: remove
|
||||
extern bool g_aspect_wide;
|
||||
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
void TakeScreenshot(ScrStrct* threadStruct)
|
||||
{
|
||||
// These will contain the final image size
|
||||
float FloatW = (float)threadStruct->W;
|
||||
float FloatH = (float)threadStruct->H;
|
||||
|
||||
// Handle aspect ratio for the final ScrStrct to look exactly like what's on screen.
|
||||
if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH)
|
||||
{
|
||||
bool use16_9 = g_aspect_wide;
|
||||
|
||||
// Check for force-settings and override.
|
||||
if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_16_9)
|
||||
use16_9 = true;
|
||||
else if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_4_3)
|
||||
use16_9 = false;
|
||||
|
||||
float Ratio = (FloatW / FloatH) / (!use16_9 ? (4.0f / 3.0f) : (16.0f / 9.0f));
|
||||
|
||||
// If ratio > 1 the picture is too wide and we have to limit the width.
|
||||
if (Ratio > 1)
|
||||
FloatW /= Ratio;
|
||||
// ratio == 1 or the image is too high, we have to limit the height.
|
||||
else
|
||||
FloatH *= Ratio;
|
||||
|
||||
// This is a bit expensive on high resolutions
|
||||
threadStruct->img->Rescale((int)FloatW, (int)FloatH, wxIMAGE_QUALITY_HIGH);
|
||||
}
|
||||
|
||||
// Save the screenshot and finally kill the wxImage object
|
||||
// This is really expensive when saving to PNG, but not at all when using BMP
|
||||
threadStruct->img->SaveFile(StrToWxStr(threadStruct->filename),
|
||||
wxBITMAP_TYPE_PNG);
|
||||
threadStruct->img->Destroy();
|
||||
|
||||
// Show success messages
|
||||
OSD::AddMessage(StringFromFormat("Saved %i x %i %s", (int)FloatW, (int)FloatH,
|
||||
threadStruct->filename.c_str()), 2000);
|
||||
delete threadStruct;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
@@ -1870,48 +1807,26 @@ bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle
|
||||
{
|
||||
u32 W = back_rc.GetWidth();
|
||||
u32 H = back_rc.GetHeight();
|
||||
u8 *data = (u8 *)malloc((sizeof(u8) * 3 * W * H));
|
||||
u8 *data = new u8[W * 4 * H];
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
|
||||
glReadPixels(back_rc.left, back_rc.bottom, W, H, GL_RGB, GL_UNSIGNED_BYTE, data);
|
||||
glReadPixels(back_rc.left, back_rc.bottom, W, H, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
|
||||
// Show failure message
|
||||
if (GL_REPORT_ERROR() != GL_NO_ERROR)
|
||||
{
|
||||
free(data);
|
||||
delete[] data;
|
||||
OSD::AddMessage("Error capturing or saving screenshot.", 2000);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Turn image upside down
|
||||
FlipImageData(data, W, H);
|
||||
FlipImageData(data, W, H, 4);
|
||||
bool success = TextureToPng(data, W*4, filename, W, H, false);
|
||||
delete[] data;
|
||||
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
// Create wxImage
|
||||
wxImage *a = new wxImage(W, H, data);
|
||||
return success;
|
||||
|
||||
if (scrshotThread.joinable())
|
||||
scrshotThread.join();
|
||||
|
||||
ScrStrct *threadStruct = new ScrStrct;
|
||||
threadStruct->filename = filename;
|
||||
threadStruct->img = a;
|
||||
threadStruct->H = H; threadStruct->W = W;
|
||||
|
||||
scrshotThread = std::thread(TakeScreenshot, threadStruct);
|
||||
#ifdef _WIN32
|
||||
SetThreadPriority(scrshotThread.native_handle(), THREAD_PRIORITY_BELOW_NORMAL);
|
||||
#endif
|
||||
bool result = true;
|
||||
|
||||
OSD::AddMessage("Saving Screenshot... ", 2000);
|
||||
|
||||
#else
|
||||
bool result = SaveTGA(filename.c_str(), W, H, data);
|
||||
free(data);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ enum GLSL_VERSION {
|
||||
GLSL_130,
|
||||
GLSL_140,
|
||||
GLSL_150, // and above
|
||||
GLSLES2,
|
||||
GLSLES3
|
||||
};
|
||||
|
||||
@@ -63,7 +62,7 @@ public:
|
||||
|
||||
void RenderText(const char* pstr, int left, int top, u32 color) override;
|
||||
void DrawDebugInfo();
|
||||
void FlipImageData(u8 *data, int w, int h);
|
||||
void FlipImageData(u8 *data, int w, int h, int pixel_width = 3);
|
||||
|
||||
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override;
|
||||
|
||||
|
||||
@@ -16,14 +16,11 @@ SamplerCache::SamplerCache()
|
||||
|
||||
SamplerCache::~SamplerCache()
|
||||
{
|
||||
if (!DriverDetails::HasBug(DriverDetails::BUG_ISTEGRA))
|
||||
Clear();
|
||||
Clear();
|
||||
}
|
||||
|
||||
void SamplerCache::SetSamplerState(int stage, const TexMode0& tm0, const TexMode1& tm1)
|
||||
{
|
||||
if (DriverDetails::HasBug(DriverDetails::BUG_ISTEGRA))
|
||||
return;
|
||||
// TODO: can this go somewhere else?
|
||||
if (m_last_max_anisotropy != g_ActiveConfig.iMaxAnisotropy)
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ StreamBuffer::StreamBuffer(u32 type, size_t size, StreamType uploadType)
|
||||
m_uploadtype = BUFFERDATA;
|
||||
else if(g_ogl_config.bSupportsGLSync && g_ActiveConfig.bHackedBufferUpload && (m_uploadtype & MAP_AND_RISK))
|
||||
m_uploadtype = MAP_AND_RISK;
|
||||
else if(g_ogl_config.bSupportsGLSync && g_ogl_config.bSupportsGLPinnedMemory && (!DriverDetails::HasBug(DriverDetails::BUG_BROKENPINNEDMEMORY) || type != GL_ELEMENT_ARRAY_BUFFER) && (m_uploadtype & PINNED_MEMORY))
|
||||
else if(g_ogl_config.bSupportsGLSync && g_ogl_config.bSupportsGLPinnedMemory && !(DriverDetails::HasBug(DriverDetails::BUG_BROKENPINNEDMEMORY) && type == GL_ELEMENT_ARRAY_BUFFER) && (m_uploadtype & PINNED_MEMORY))
|
||||
m_uploadtype = PINNED_MEMORY;
|
||||
else if(nvidia && (m_uploadtype & BUFFERSUBDATA))
|
||||
m_uploadtype = BUFFERSUBDATA;
|
||||
@@ -59,7 +59,7 @@ StreamBuffer::~StreamBuffer()
|
||||
glDeleteBuffers(1, &m_buffer);
|
||||
}
|
||||
|
||||
#define SLOT(x) (x)*SYNC_POINTS/m_size
|
||||
#define SLOT(x) ((x)*SYNC_POINTS/m_size)
|
||||
|
||||
void StreamBuffer::Alloc ( size_t size, u32 stride )
|
||||
{
|
||||
@@ -81,14 +81,14 @@ void StreamBuffer::Alloc ( size_t size, u32 stride )
|
||||
case PINNED_MEMORY:
|
||||
|
||||
// insert waiting slots for used memory
|
||||
for(u32 i=SLOT(m_used_iterator); i<SLOT(m_iterator); i++)
|
||||
for(size_t i=SLOT(m_used_iterator); i<SLOT(m_iterator); i++)
|
||||
{
|
||||
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
}
|
||||
m_used_iterator = m_iterator;
|
||||
|
||||
// wait for new slots to end of buffer
|
||||
for(u32 i=SLOT(m_free_iterator)+1; i<=SLOT(iter_end) && i < SYNC_POINTS; i++)
|
||||
for (size_t i = SLOT(m_free_iterator) + 1; i <= SLOT(iter_end) && i < SYNC_POINTS; i++)
|
||||
{
|
||||
glClientWaitSync(fences[i], GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
|
||||
glDeleteSync(fences[i]);
|
||||
@@ -99,8 +99,10 @@ void StreamBuffer::Alloc ( size_t size, u32 stride )
|
||||
if(iter_end >= m_size) {
|
||||
|
||||
// insert waiting slots in unused space at the end of the buffer
|
||||
for(u32 i=SLOT(m_used_iterator); i < SYNC_POINTS; i++)
|
||||
for (size_t i = SLOT(m_used_iterator); i < SYNC_POINTS; i++)
|
||||
{
|
||||
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
}
|
||||
|
||||
// move to the start
|
||||
m_used_iterator = m_iterator_aligned = m_iterator = 0; // offset 0 is always aligned
|
||||
@@ -244,10 +246,14 @@ void StreamBuffer::Shutdown()
|
||||
|
||||
void StreamBuffer::DeleteFences()
|
||||
{
|
||||
for(u32 i=SLOT(m_free_iterator)+1; i < SYNC_POINTS; i++)
|
||||
for (size_t i = SLOT(m_free_iterator) + 1; i < SYNC_POINTS; i++)
|
||||
{
|
||||
glDeleteSync(fences[i]);
|
||||
for(u32 i=0; i<SLOT(m_iterator); i++)
|
||||
}
|
||||
for (size_t i = 0; i < SLOT(m_iterator); i++)
|
||||
{
|
||||
glDeleteSync(fences[i]);
|
||||
}
|
||||
delete [] fences;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,15 +59,15 @@ struct VBOCache {
|
||||
};
|
||||
static std::map<u64,VBOCache> s_VBO;
|
||||
|
||||
bool SaveTexture(const char* filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level)
|
||||
bool SaveTexture(const std::string filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level)
|
||||
{
|
||||
#ifndef USE_GLES3
|
||||
int width = std::max(virtual_width >> level, 1);
|
||||
int height = std::max(virtual_height >> level, 1);
|
||||
std::vector<u32> data(width * height);
|
||||
u8* data = new u8[width * height * 4];
|
||||
glActiveTexture(GL_TEXTURE0+9);
|
||||
glBindTexture(textarget, tex);
|
||||
glGetTexImage(textarget, level, GL_BGRA, GL_UNSIGNED_BYTE, &data[0]);
|
||||
glGetTexImage(textarget, level, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
glBindTexture(textarget, 0);
|
||||
TextureCache::SetStage();
|
||||
|
||||
@@ -75,10 +75,12 @@ bool SaveTexture(const char* filename, u32 textarget, u32 tex, int virtual_width
|
||||
if (GL_NO_ERROR != err)
|
||||
{
|
||||
PanicAlert("Can't save texture, GL Error: %s", gluErrorString(err));
|
||||
delete[] data;
|
||||
return false;
|
||||
}
|
||||
|
||||
return SaveTGA(filename, width, height, &data[0]);
|
||||
bool success = TextureToPng(data, width * 4, filename, width, height, true);
|
||||
delete[] data;
|
||||
return success;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
@@ -125,13 +127,9 @@ void TextureCache::TCacheEntry::Bind(unsigned int stage)
|
||||
}
|
||||
}
|
||||
|
||||
bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
|
||||
bool TextureCache::TCacheEntry::Save(const std::string filename, unsigned int level)
|
||||
{
|
||||
// TODO: make ogl dump PNGs
|
||||
std::string tga_filename(filename);
|
||||
tga_filename.replace(tga_filename.size() - 3, 3, "tga");
|
||||
|
||||
return SaveTexture(tga_filename.c_str(), GL_TEXTURE_2D, texture, virtual_width, virtual_height, level);
|
||||
return SaveTexture(filename, GL_TEXTURE_2D, texture, virtual_width, virtual_height, level);
|
||||
}
|
||||
|
||||
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
|
||||
@@ -395,8 +393,8 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
||||
if (g_ActiveConfig.bDumpEFBTarget)
|
||||
{
|
||||
static int count = 0;
|
||||
SaveTexture(StringFromFormat("%sefb_frame_%i.tga", File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
|
||||
count++).c_str(), GL_TEXTURE_2D, texture, virtual_width, virtual_height, 0);
|
||||
SaveTexture(StringFromFormat("%sefb_frame_%i.png", File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
|
||||
count++), GL_TEXTURE_2D, texture, virtual_width, virtual_height, 0);
|
||||
}
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
|
||||
@@ -53,7 +53,7 @@ private:
|
||||
const float *colmat) override;
|
||||
|
||||
void Bind(unsigned int stage) override;
|
||||
bool Save(const char filename[], unsigned int level);
|
||||
bool Save(const std::string filename, unsigned int level);
|
||||
};
|
||||
|
||||
~TextureCache();
|
||||
@@ -64,7 +64,7 @@ private:
|
||||
TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h) override;
|
||||
};
|
||||
|
||||
bool SaveTexture(const char* filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level);
|
||||
bool SaveTexture(const std::string filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,6 @@ using OGL::TextureCache;
|
||||
|
||||
static GLuint s_texConvFrameBuffer = 0;
|
||||
static GLuint s_srcTexture = 0; // for decoding from RAM
|
||||
static GLuint s_srcTextureWidth = 0;
|
||||
static GLuint s_srcTextureHeight = 0;
|
||||
static GLuint s_dstTexture = 0; // for encoding to RAM
|
||||
|
||||
const int renderBufferWidth = 1024;
|
||||
@@ -44,11 +42,8 @@ static SHADER s_encodingPrograms[NUM_ENCODING_PROGRAMS];
|
||||
|
||||
static GLuint s_encode_VBO = 0;
|
||||
static GLuint s_encode_VAO = 0;
|
||||
static GLuint s_decode_VBO = 0;
|
||||
static GLuint s_decode_VAO = 0;
|
||||
static TargetRectangle s_cached_sourceRc;
|
||||
static int s_cached_srcWidth = 0;
|
||||
static int s_cached_srcHeight = 0;
|
||||
|
||||
static const char *VProgram =
|
||||
"ATTRIN vec2 rawpos;\n"
|
||||
@@ -62,6 +57,22 @@ static const char *VProgram =
|
||||
|
||||
void CreatePrograms()
|
||||
{
|
||||
/* TODO: Accuracy Improvements
|
||||
*
|
||||
* This shader doesn't really match what the gamecube does interally in the
|
||||
* copy pipeline.
|
||||
* 1. It uses Opengl's built in filtering when yscaling, someone could work
|
||||
* out how the copypipeline does it's filtering and implement it correctly
|
||||
* in this shader.
|
||||
* 2. Deflickering isn't implemented, a futher filtering over 3 lines.
|
||||
* Isn't really needed on non-interlaced monitors (and would lower quality;
|
||||
* But hey, accuracy!)
|
||||
* 3. Flipper's YUYV conversion implements a 3 pixel horozontal blur on the
|
||||
* UV channels, centering the U channel on the Left pixel and the V channel
|
||||
* on the Right pixel.
|
||||
* The current implementation Centers both UV channels at the same place
|
||||
* inbetween the two Pixels, and only blurs over these two pixels.
|
||||
*/
|
||||
// Output is BGRA because that is slightly faster than RGBA.
|
||||
const char *FProgramRgbToYuyv =
|
||||
"uniform sampler2DRect samp9;\n"
|
||||
@@ -69,8 +80,8 @@ void CreatePrograms()
|
||||
"COLOROUT(ocol0)\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec3 c0 = texture2DRect(samp9, uv0).rgb;\n"
|
||||
" vec3 c1 = texture2DRect(samp9, uv0 + vec2(1.0, 0.0)).rgb;\n"
|
||||
" vec3 c0 = texture2DRect(samp9, uv0 - dFdx(uv0) * 0.25).rgb;\n"
|
||||
" vec3 c1 = texture2DRect(samp9, uv0 + dFdx(uv0) * 0.25).rgb;\n"
|
||||
" vec3 c01 = (c0 + c1) * 0.5;\n"
|
||||
" vec3 y_const = vec3(0.257,0.504,0.098);\n"
|
||||
" vec3 u_const = vec3(-0.148,-0.291,0.439);\n"
|
||||
@@ -79,15 +90,35 @@ void CreatePrograms()
|
||||
" ocol0 = vec4(dot(c1,y_const),dot(c01,u_const),dot(c0,y_const),dot(c01, v_const)) + const3;\n"
|
||||
"}\n";
|
||||
|
||||
/* TODO: Accuracy Improvements
|
||||
*
|
||||
* The YVYU to RGB conversion here matches the RGB to YUYV done above, but
|
||||
* if a game modifies or adds images to the XFB then it should be using the
|
||||
* same algorithm as the flipper, and could result in slight colour inaccuracies
|
||||
* when run back through this shader.
|
||||
*/
|
||||
const char *VProgramYuyvToRgb =
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n"
|
||||
" gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n"
|
||||
"}\n";
|
||||
const char *FProgramYuyvToRgb =
|
||||
"uniform sampler2DRect samp9;\n"
|
||||
"VARYIN vec2 uv0;\n"
|
||||
"COLOROUT(ocol0)\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec4 c0 = texture2DRect(samp9, uv0).rgba;\n"
|
||||
" float f = step(0.5, fract(uv0.x));\n"
|
||||
" float y = mix(c0.b, c0.r, f);\n"
|
||||
" ivec2 uv = ivec2(gl_FragCoord.xy);\n"
|
||||
#ifdef USE_GLES3
|
||||
// We switch top/bottom here. TODO: move this to screen blit.
|
||||
" ivec2 ts = textureSize(samp9, 0);\n"
|
||||
" vec4 c0 = texelFetch(samp9, ivec2(uv.x/2, ts.y-uv.y-1), 0);\n"
|
||||
#else
|
||||
" ivec2 ts = textureSize(samp9);\n"
|
||||
" vec4 c0 = texelFetch(samp9, ivec2(uv.x/2, ts.y-uv.y-1));\n"
|
||||
#endif
|
||||
" float y = mix(c0.b, c0.r, uv.x & 1);\n"
|
||||
" float yComp = 1.164 * (y - 0.0625);\n"
|
||||
" float uComp = c0.g - 0.5;\n"
|
||||
" float vComp = c0.a - 0.5;\n"
|
||||
@@ -98,7 +129,7 @@ void CreatePrograms()
|
||||
"}\n";
|
||||
|
||||
ProgramShaderCache::CompileShader(s_rgbToYuyvProgram, VProgram, FProgramRgbToYuyv);
|
||||
ProgramShaderCache::CompileShader(s_yuyvToRgbProgram, VProgram, FProgramYuyvToRgb);
|
||||
ProgramShaderCache::CompileShader(s_yuyvToRgbProgram, VProgramYuyvToRgb, FProgramYuyvToRgb);
|
||||
}
|
||||
|
||||
SHADER &GetOrCreateEncodingShader(u32 format)
|
||||
@@ -146,19 +177,8 @@ void Init()
|
||||
s_cached_sourceRc.left = -1;
|
||||
s_cached_sourceRc.right = -1;
|
||||
|
||||
glGenBuffers(1, &s_decode_VBO );
|
||||
glGenVertexArrays(1, &s_decode_VAO );
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_decode_VBO );
|
||||
glBindVertexArray( s_decode_VAO );
|
||||
s_cached_srcWidth = -1;
|
||||
s_cached_srcHeight = -1;
|
||||
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL);
|
||||
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
|
||||
|
||||
s_srcTextureWidth = 0;
|
||||
s_srcTextureHeight = 0;
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + 9);
|
||||
glGenTextures(1, &s_srcTexture);
|
||||
@@ -180,7 +200,6 @@ void Shutdown()
|
||||
glDeleteFramebuffers(1, &s_texConvFrameBuffer);
|
||||
glDeleteBuffers(1, &s_encode_VBO );
|
||||
glDeleteVertexArrays(1, &s_encode_VAO );
|
||||
glDeleteBuffers(1, &s_decode_VBO );
|
||||
glDeleteVertexArrays(1, &s_decode_VAO );
|
||||
|
||||
s_rgbToYuyvProgram.Destroy();
|
||||
@@ -347,7 +366,10 @@ void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* des
|
||||
|
||||
s_rgbToYuyvProgram.Bind();
|
||||
|
||||
EncodeToRamUsingShader(srcTexture, sourceRc, destAddr, dstWidth / 2, dstHeight, 0, false, false);
|
||||
// We enable linear filtering, because the gamecube does filtering in the vertical direction when
|
||||
// yscale is enabled.
|
||||
// Otherwise we get jaggies when a game uses yscaling (most PAL games)
|
||||
EncodeToRamUsingShader(srcTexture, sourceRc, destAddr, dstWidth / 2, dstHeight, 0, false, true);
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
TextureCache::DisableStage(0);
|
||||
g_renderer->RestoreAPIState();
|
||||
@@ -365,8 +387,6 @@ void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTextur
|
||||
return;
|
||||
}
|
||||
|
||||
int srcFmtWidth = srcWidth / 2;
|
||||
|
||||
g_renderer->ResetAPIState(); // reset any game specific settings
|
||||
|
||||
// switch to texture converter frame buffer
|
||||
@@ -380,50 +400,14 @@ void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTextur
|
||||
// set srcAddr as data for source texture
|
||||
glActiveTexture(GL_TEXTURE0+9);
|
||||
glBindTexture(getFbType(), s_srcTexture);
|
||||
|
||||
// TODO: make this less slow. (How?)
|
||||
if ((GLsizei)s_srcTextureWidth == (GLsizei)srcFmtWidth && (GLsizei)s_srcTextureHeight == (GLsizei)srcHeight)
|
||||
{
|
||||
glTexSubImage2D(getFbType(), 0,0,0,s_srcTextureWidth, s_srcTextureHeight,
|
||||
GL_BGRA, GL_UNSIGNED_BYTE, srcAddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexImage2D(getFbType(), 0, GL_RGBA, (GLsizei)srcFmtWidth, (GLsizei)srcHeight,
|
||||
0, GL_BGRA, GL_UNSIGNED_BYTE, srcAddr);
|
||||
s_srcTextureWidth = (GLsizei)srcFmtWidth;
|
||||
s_srcTextureHeight = (GLsizei)srcHeight;
|
||||
}
|
||||
glTexImage2D(getFbType(), 0, GL_RGBA, srcWidth / 2, srcHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, srcAddr);
|
||||
|
||||
glViewport(0, 0, srcWidth, srcHeight);
|
||||
s_yuyvToRgbProgram.Bind();
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
if(s_cached_srcHeight != srcHeight || s_cached_srcWidth != srcWidth) {
|
||||
GLfloat vertices[] = {
|
||||
1.f, -1.f,
|
||||
(float)srcFmtWidth, (float)srcHeight,
|
||||
1.f, 1.f,
|
||||
(float)srcFmtWidth, 0.f,
|
||||
-1.f, -1.f,
|
||||
0.f, (float)srcHeight,
|
||||
-1.f, 1.f,
|
||||
0.f, 0.f
|
||||
};
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_decode_VBO );
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*4*4, vertices, GL_STREAM_DRAW);
|
||||
|
||||
s_cached_srcHeight = srcHeight;
|
||||
s_cached_srcWidth = srcWidth;
|
||||
}
|
||||
|
||||
glBindVertexArray( s_decode_VAO );
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user