diff --git a/Source/Android/AndroidManifest.xml b/Source/Android/AndroidManifest.xml index 80fb93470e..95d8b9a174 100644 --- a/Source/Android/AndroidManifest.xml +++ b/Source/Android/AndroidManifest.xml @@ -33,6 +33,7 @@ + ビルドのバージョン サポートのOpenGL ES 3 サポートのNEON + CPU + GLES 2 + GLES 3 + OpenGL + + + CPU ABI 1 + CPU ABI 2 + CPU情報 + CPUタイプ + CPUの命令セットと機能 + CPUコア + CPUの実装 + ハードウェア + 不明 (%1$d)。 我々はそれを文書化することができますので、この番号を報告してください。 現在のディレクトリ: %1$s diff --git a/Source/Android/res/values/strings.xml b/Source/Android/res/values/strings.xml index 3557261e66..0fae5bab6c 100644 --- a/Source/Android/res/values/strings.xml +++ b/Source/Android/res/values/strings.xml @@ -12,6 +12,22 @@ Build Revision Supports OpenGL ES 3 Supports NEON + General + CPU + GLES 2 + GLES 3 + OpenGL + + + CPU ABI 1 + CPU ABI 2 + CPU Info + CPU Type + CPU Features + Number of Cores + CPU Implementer + Hardware + Unknown (%1$d). Please report this number so it can be documented! Current Dir: %1$s diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/AboutFragment.java b/Source/Android/src/org/dolphinemu/dolphinemu/AboutFragment.java deleted file mode 100644 index 6ca90a2577..0000000000 --- a/Source/Android/src/org/dolphinemu/dolphinemu/AboutFragment.java +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Copyright 2013 Dolphin Emulator Project - * Licensed under GPLv2 - * Refer to the license.txt file included. - */ - -package org.dolphinemu.dolphinemu; - -import android.app.ListFragment; -import android.content.Context; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.ListView; -import android.widget.TextView; - -import java.util.ArrayList; -import java.util.List; - -import org.dolphinemu.dolphinemu.settings.video.VideoSettingsFragment; - -/** - * Represents the about screen. - */ -public final class AboutFragment extends ListFragment -{ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) - { - ListView rootView = (ListView) inflater.inflate(R.layout.gamelist_listview, container, false); - - final String yes = getString(R.string.yes); - final String no = getString(R.string.no); - - List Input = new ArrayList(); - 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); - rootView.setAdapter(adapter); - rootView.setEnabled(false); // Makes the list view non-clickable. - - return rootView; - } - - // Represents an item in the AboutFragment. - private static final class AboutFragmentItem - { - private final String title; - private final String subtitle; - - public AboutFragmentItem(String title, String subtitle) - { - this.title = title; - this.subtitle = subtitle; - } - - public String getTitle() - { - return title; - } - - public String getSubTitle() - { - return subtitle; - } - } - - // The adapter that manages the displaying of items in this AboutFragment. - private static final class AboutFragmentAdapter extends ArrayAdapter - { - private final Context ctx; - private final int id; - private final List items; - - public AboutFragmentAdapter(Context ctx, int id, List items) - { - super(ctx, id, items); - - this.ctx = ctx; - this.id = id; - this.items = items; - } - - @Override - public AboutFragmentItem getItem(int index) - { - return items.get(index); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) - { - if (convertView == null) - { - LayoutInflater vi = LayoutInflater.from(ctx); - convertView = vi.inflate(id, parent, false); - } - - final AboutFragmentItem item = items.get(position); - if (item != null) - { - TextView title = (TextView) convertView.findViewById(R.id.AboutItemTitle); - TextView subtitle = (TextView) convertView.findViewById(R.id.AboutItemSubTitle); - - if (title != null) - title.setText(item.getTitle()); - - if (subtitle != null) - subtitle.setText(item.getSubTitle()); - } - - return convertView; - } - } -} diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/about/AboutActivity.java b/Source/Android/src/org/dolphinemu/dolphinemu/about/AboutActivity.java new file mode 100644 index 0000000000..d544d7e6c2 --- /dev/null +++ b/Source/Android/src/org/dolphinemu/dolphinemu/about/AboutActivity.java @@ -0,0 +1,249 @@ +package org.dolphinemu.dolphinemu.about; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.utils.EGLHelper; + +import android.app.ActionBar; +import android.app.ActionBar.Tab; +import android.app.ActionBar.TabListener; +import android.app.Activity; +import android.app.Fragment; +import android.app.FragmentManager; +import android.app.FragmentTransaction; +import android.content.Context; +import android.os.Bundle; +import android.support.v13.app.FragmentPagerAdapter; +import android.support.v4.view.ViewPager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; + +import java.util.List; + +/** + * Activity for the about menu, which displays info + * related to the CPU and GPU. Along with misc other info. + */ +public final class AboutActivity extends Activity implements TabListener +{ + private ViewPager viewPager; + private final EGLHelper eglHelper = new EGLHelper(EGLHelper.EGL_OPENGL_ES2_BIT); + + // Represents an item in the multiple About fragments. + public static final class AboutFragmentItem + { + private final String title; + private final String subtitle; + + public AboutFragmentItem(String title, String subtitle) + { + this.title = title; + this.subtitle = subtitle; + } + + public String getTitle() + { + return title; + } + + public String getSubTitle() + { + return subtitle; + } + } + + // The adapter that manages the displaying of items in multiple About fragments. + public static final class InfoFragmentAdapter extends ArrayAdapter + { + private final int id; + private final List items; + + public InfoFragmentAdapter(Context ctx, int id, List items) + { + super(ctx, id, items); + + this.id = id; + this.items = items; + } + + @Override + public AboutFragmentItem getItem(int index) + { + return items.get(index); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) + { + if (convertView == null) + { + LayoutInflater vi = LayoutInflater.from(getContext()); + convertView = vi.inflate(id, parent, false); + } + + final AboutFragmentItem item = items.get(position); + if (item != null) + { + TextView title = (TextView) convertView.findViewById(R.id.AboutItemTitle); + TextView subtitle = (TextView) convertView.findViewById(R.id.AboutItemSubTitle); + + if (title != null) + title.setText(item.getTitle()); + + if (subtitle != null) + subtitle.setText(item.getSubTitle()); + } + + return convertView; + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + // Set the view pager + setContentView(R.layout.viewpager); + viewPager = (ViewPager) findViewById(R.id.pager); + + // Initialize the ViewPager adapter. + final ViewPagerAdapter adapter = new ViewPagerAdapter(getFragmentManager()); + viewPager.setAdapter(adapter); + + // Set up the ActionBar + final ActionBar actionBar = getActionBar(); + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); + actionBar.addTab(actionBar.newTab().setText(R.string.general).setTabListener(this)); + actionBar.addTab(actionBar.newTab().setText(R.string.cpu).setTabListener(this)); + actionBar.addTab(actionBar.newTab().setText(R.string.gles_two).setTabListener(this)); + if (eglHelper.supportsGLES3()) + actionBar.addTab(actionBar.newTab().setText(R.string.gles_three).setTabListener(this)); + if (eglHelper.supportsOpenGL()) + actionBar.addTab(actionBar.newTab().setText(R.string.desktop_gl).setTabListener(this)); + + // Set the page change listener + viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() + { + @Override + public void onPageSelected(int position) + { + actionBar.setSelectedNavigationItem(position); + } + }); + } + + @Override + public void onDestroy() + { + super.onDestroy(); + + eglHelper.closeHelper(); + } + + @Override + public void onTabSelected(Tab tab, FragmentTransaction ft) + { + // When the given tab is selected, switch to the corresponding page in the ViewPager. + viewPager.setCurrentItem(tab.getPosition()); + } + + @Override + public void onTabReselected(Tab tab, FragmentTransaction ft) + { + // Do nothing. + } + + @Override + public void onTabUnselected(Tab tab, FragmentTransaction ft) + { + // Do nothing. + } + + /** + * {@link FragmentPagerAdapter} subclass responsible for handling + * the individual {@link Fragment}s within the {@link ViewPager}. + */ + private final class ViewPagerAdapter extends FragmentPagerAdapter + { + public ViewPagerAdapter(FragmentManager fm) + { + super(fm); + } + + @Override + public Fragment getItem(int position) + { + if (position == 0) + { + return new DolphinInfoFragment(); + } + else if (position == 1) + { + return new CPUInfoFragment(); // CPU + } + else if (position == 2) // GLES 2 + { + return new GLES2InfoFragment(); + } + else if (position == 3) // GLES 3 or OpenGL (depending on circumstances) + { + if (eglHelper.supportsGLES3()) + return new GLES3InfoFragment(); + else + return new GLInfoFragment(); // GLES3 not supported, but OpenGL is. + } + else if (position == 4) // OpenGL fragment + { + return new GLInfoFragment(); + } + + // This should never happen. + return null; + } + + @Override + public int getCount() + { + if (eglHelper.supportsGLES3() && eglHelper.supportsOpenGL()) + { + return 5; + } + else if (!eglHelper.supportsGLES3() && !eglHelper.supportsOpenGL()) + { + return 3; + } + else // Either regular OpenGL or GLES3 isn't supported + { + return 4; + } + } + + @Override + public CharSequence getPageTitle(int position) + { + switch (position) + { + case 0: + return getString(R.string.general); + + case 1: + return getString(R.string.cpu); + + case 2: + return getString(R.string.gles_two); + + case 3: + return getString(R.string.gles_three); + + case 4: + return getString(R.string.desktop_gl); + + default: // Should never happen + return null; + } + } + } +} diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/about/CPUInfoFragment.java b/Source/Android/src/org/dolphinemu/dolphinemu/about/CPUInfoFragment.java new file mode 100644 index 0000000000..ddf1e0f816 --- /dev/null +++ b/Source/Android/src/org/dolphinemu/dolphinemu/about/CPUInfoFragment.java @@ -0,0 +1,47 @@ +package org.dolphinemu.dolphinemu.about; + +import java.util.ArrayList; +import java.util.List; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.about.AboutActivity.AboutFragmentItem; +import org.dolphinemu.dolphinemu.utils.CPUHelper; + +import android.app.ListFragment; +import android.os.Build; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; + +/** + * {@link ListFragment class that is responsible + * for displaying information related to the CPU. + */ +public final class CPUInfoFragment extends ListFragment +{ + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) + { + ListView rootView = (ListView) inflater.inflate(R.layout.gamelist_listview, container, false); + List items = new ArrayList(); + + CPUHelper cpuHelper = new CPUHelper(getActivity()); + + items.add(new AboutFragmentItem(getString(R.string.cpu_info), cpuHelper.getProcessorInfo())); + items.add(new AboutFragmentItem(getString(R.string.cpu_type), cpuHelper.getProcessorType())); + items.add(new AboutFragmentItem(getString(R.string.cpu_abi_one), Build.CPU_ABI)); + items.add(new AboutFragmentItem(getString(R.string.cpu_abi_two), Build.CPU_ABI2)); + items.add(new AboutFragmentItem(getString(R.string.num_cores), Integer.toString(cpuHelper.getNumCores()))); + items.add(new AboutFragmentItem(getString(R.string.cpu_features), cpuHelper.getFeatures())); + items.add(new AboutFragmentItem(getString(R.string.cpu_hardware), Build.HARDWARE)); + if (CPUHelper.isARM()) + items.add(new AboutFragmentItem(getString(R.string.cpu_implementer), cpuHelper.getImplementer())); + + AboutActivity.InfoFragmentAdapter adapter = new AboutActivity.InfoFragmentAdapter(getActivity(), R.layout.about_layout, items); + rootView.setAdapter(adapter); + + return rootView; + } +} diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/about/DolphinInfoFragment.java b/Source/Android/src/org/dolphinemu/dolphinemu/about/DolphinInfoFragment.java new file mode 100644 index 0000000000..af7d1a14e2 --- /dev/null +++ b/Source/Android/src/org/dolphinemu/dolphinemu/about/DolphinInfoFragment.java @@ -0,0 +1,50 @@ +/** + * Copyright 2013 Dolphin Emulator Project + * Licensed under GPLv2 + * Refer to the license.txt file included. + */ + +package org.dolphinemu.dolphinemu.about; + +import android.app.ListFragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; + +import java.util.ArrayList; +import java.util.List; + +import org.dolphinemu.dolphinemu.NativeLibrary; +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.about.AboutActivity.AboutFragmentItem; +import org.dolphinemu.dolphinemu.about.AboutActivity.InfoFragmentAdapter; +import org.dolphinemu.dolphinemu.utils.EGLHelper; + +/** + * Represents the about screen. + */ +public final class DolphinInfoFragment extends ListFragment +{ + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) + { + ListView rootView = (ListView) inflater.inflate(R.layout.gamelist_listview, container, false); + EGLHelper eglHelper = new EGLHelper(EGLHelper.EGL_OPENGL_ES2_BIT); + + final String yes = getString(R.string.yes); + final String no = getString(R.string.no); + + List Input = new ArrayList(); + Input.add(new AboutFragmentItem(getString(R.string.build_revision), NativeLibrary.GetVersionString())); + Input.add(new AboutFragmentItem(getString(R.string.supports_gles3), eglHelper.supportsGLES3() ? yes : no)); + Input.add(new AboutFragmentItem(getString(R.string.supports_neon), NativeLibrary.SupportsNEON() ? yes : no)); + + InfoFragmentAdapter adapter = new InfoFragmentAdapter(getActivity(), R.layout.about_layout, Input); + rootView.setAdapter(adapter); + rootView.setEnabled(false); // Makes the list view non-clickable. + + return rootView; + } +} diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/about/GLES2InfoFragment.java b/Source/Android/src/org/dolphinemu/dolphinemu/about/GLES2InfoFragment.java new file mode 100644 index 0000000000..12d5374d79 --- /dev/null +++ b/Source/Android/src/org/dolphinemu/dolphinemu/about/GLES2InfoFragment.java @@ -0,0 +1,82 @@ +/** + * Copyright 2013 Dolphin Emulator Project + * Licensed under GPLv2 + * Refer to the license.txt file included. + */ + +package org.dolphinemu.dolphinemu.about; + +import android.app.ListFragment; +import android.opengl.GLES20; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.about.Limit.Type; +import org.dolphinemu.dolphinemu.utils.EGLHelper; + +import java.util.ArrayList; +import java.util.List; + +/** + * {@link ListFragment} responsible for displaying + * information relating to OpenGL ES 2. + */ +public final class GLES2InfoFragment extends ListFragment +{ + private final EGLHelper eglHelper = new EGLHelper(EGLHelper.EGL_OPENGL_ES2_BIT); + + private final Limit[] Limits = { + new Limit("Vendor", GLES20.GL_VENDOR, Type.STRING), + new Limit("Version", GLES20.GL_VERSION, Type.STRING), + new Limit("Renderer", GLES20.GL_RENDERER, Type.STRING), + new Limit("GLSL version", GLES20.GL_SHADING_LANGUAGE_VERSION, Type.STRING), + // GLES 2.0 Limits + //new Limit("Aliased Point Size", GLES20.GL_ALIASED_POINT_SIZE_RANGE, Type.INTEGER_RANGE), + //new Limit("Aliased Line Width ", GLES20.GL_ALIASED_LINE_WIDTH_RANGE, Type.INTEGER_RANGE), + new Limit("Max Texture Size", GLES20.GL_MAX_TEXTURE_SIZE, Type.INTEGER), + //new Limit("Viewport Dimensions", GLES20.GL_MAX_VIEWPORT_DIMS, Type.INTEGER_RANGE), + new Limit("Subpixel Bits", GLES20.GL_SUBPIXEL_BITS, Type.INTEGER), + new Limit("Max Vertex Attributes", GLES20.GL_MAX_VERTEX_ATTRIBS, Type.INTEGER), + new Limit("Max Vertex Uniform Vectors", GLES20.GL_MAX_VERTEX_UNIFORM_VECTORS, Type.INTEGER), + new Limit("Max Varying Vectors", GLES20.GL_MAX_VARYING_VECTORS, Type.INTEGER), + new Limit("Max Combined Texture Units", GLES20.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, Type.INTEGER), + new Limit("Max Vertex Texture Units", GLES20.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, Type.INTEGER), + new Limit("Max Texture Units", GLES20.GL_MAX_TEXTURE_IMAGE_UNITS, Type.INTEGER), + new Limit("Max Fragment Uniform Vectors", GLES20.GL_MAX_FRAGMENT_UNIFORM_VECTORS, Type.INTEGER), + new Limit("Max Cubemap Texture Size", GLES20.GL_MAX_CUBE_MAP_TEXTURE_SIZE, Type.INTEGER), + new Limit("Shader Binary Formats", GLES20.GL_NUM_SHADER_BINARY_FORMATS, Type.INTEGER), + new Limit("Max Framebuffer Size", GLES20.GL_MAX_RENDERBUFFER_SIZE, Type.INTEGER), + }; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) + { + ListView rootView = (ListView) inflater.inflate(R.layout.gamelist_listview, container, false); + List Input = new ArrayList(); + + for (Limit limit : Limits) + { + Log.i("GLES2InfoFragment", "Getting enum " + limit.name); + Input.add(new AboutActivity.AboutFragmentItem(limit.name, limit.GetValue(eglHelper))); + } + + // Get extensions manually + String[] extensions = eglHelper.glGetString(GLES20.GL_EXTENSIONS).split(" "); + StringBuilder extensionsBuilder = new StringBuilder(); + for (String extension : extensions) + { + extensionsBuilder.append(extension).append('\n'); + } + Input.add(new AboutActivity.AboutFragmentItem("OpenGL ES 2.0 Extensions", extensionsBuilder.toString())); + + AboutActivity.InfoFragmentAdapter adapter = new AboutActivity.InfoFragmentAdapter(getActivity(), R.layout.about_layout, Input); + rootView.setAdapter(adapter); + + return rootView; + } +} diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/about/GLES3InfoFragment.java b/Source/Android/src/org/dolphinemu/dolphinemu/about/GLES3InfoFragment.java new file mode 100644 index 0000000000..797a047b14 --- /dev/null +++ b/Source/Android/src/org/dolphinemu/dolphinemu/about/GLES3InfoFragment.java @@ -0,0 +1,114 @@ +/** + * Copyright 2013 Dolphin Emulator Project + * Licensed under GPLv2 + * Refer to the license.txt file included. + */ + +package org.dolphinemu.dolphinemu.about; + +import android.app.ListFragment; +import android.opengl.GLES30; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.about.Limit.Type; +import org.dolphinemu.dolphinemu.utils.EGLHelper; + +import java.util.ArrayList; +import java.util.List; + +/** + * {@link ListFragment} responsible for displaying + * information relating to OpenGL ES 3. + */ +public final class GLES3InfoFragment extends ListFragment +{ + private final EGLHelper eglHelper = new EGLHelper(EGLHelper.EGL_OPENGL_ES3_BIT_KHR); + + private final Limit[] Limits = { + new Limit("Vendor", GLES30.GL_VENDOR, Type.STRING), + new Limit("Version", GLES30.GL_VERSION, Type.STRING), + new Limit("Renderer", GLES30.GL_RENDERER, Type.STRING), + new Limit("GLSL version", GLES30.GL_SHADING_LANGUAGE_VERSION, Type.STRING), + // GLES 2.0 Limits + new Limit("Aliased Point Size", GLES30.GL_ALIASED_POINT_SIZE_RANGE, Type.INTEGER_RANGE), + new Limit("Aliased Line Width ", GLES30.GL_ALIASED_LINE_WIDTH_RANGE, Type.INTEGER_RANGE), + new Limit("Max Texture Size", GLES30.GL_MAX_TEXTURE_SIZE, Type.INTEGER), + new Limit("Viewport Dimensions", GLES30.GL_MAX_VIEWPORT_DIMS, Type.INTEGER_RANGE), + new Limit("Subpixel Bits", GLES30.GL_SUBPIXEL_BITS, Type.INTEGER), + new Limit("Max Vertex Attributes", GLES30.GL_MAX_VERTEX_ATTRIBS, Type.INTEGER), + new Limit("Max Vertex Uniform Vectors", GLES30.GL_MAX_VERTEX_UNIFORM_VECTORS, Type.INTEGER), + new Limit("Max Varying Vectors", GLES30.GL_MAX_VARYING_VECTORS, Type.INTEGER), + new Limit("Max Combined Texture Units", GLES30.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, Type.INTEGER), + new Limit("Max Vertex Texture Units", GLES30.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, Type.INTEGER), + new Limit("Max Texture Units", GLES30.GL_MAX_TEXTURE_IMAGE_UNITS, Type.INTEGER), + new Limit("Max Fragment Uniform Vectors", GLES30.GL_MAX_FRAGMENT_UNIFORM_VECTORS, Type.INTEGER), + new Limit("Max Cubemap Texture Size", GLES30.GL_MAX_CUBE_MAP_TEXTURE_SIZE, Type.INTEGER), + new Limit("Shader Binary Formats", GLES30.GL_NUM_SHADER_BINARY_FORMATS, Type.INTEGER), + new Limit("Max Framebuffer Size", GLES30.GL_MAX_RENDERBUFFER_SIZE, Type.INTEGER), + // GLES 3.0 limits + new Limit("Max 3D Texture size", GLES30.GL_MAX_3D_TEXTURE_SIZE, Type.INTEGER), + new Limit("Max Element Vertices", GLES30.GL_MAX_ELEMENTS_VERTICES, Type.INTEGER), + new Limit("Max Element Indices", GLES30.GL_MAX_ELEMENTS_INDICES, Type.INTEGER), + new Limit("Max Draw Buffers", GLES30.GL_MAX_DRAW_BUFFERS, Type.INTEGER), + new Limit("Max Fragment Uniform Components", GLES30.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, Type.INTEGER), + new Limit("Max Vertex Uniform Components", GLES30.GL_MAX_VERTEX_UNIFORM_COMPONENTS, Type.INTEGER), + new Limit("Number of Extensions", GLES30.GL_NUM_EXTENSIONS, Type.INTEGER), + new Limit("Max Array Texture Layers", GLES30.GL_MAX_ARRAY_TEXTURE_LAYERS, Type.INTEGER), + new Limit("Min Program Texel Offset", GLES30.GL_MIN_PROGRAM_TEXEL_OFFSET, Type.INTEGER), + new Limit("Max Program Texel Offset", GLES30.GL_MAX_PROGRAM_TEXEL_OFFSET, Type.INTEGER), + new Limit("Max Varying Components", GLES30.GL_MAX_VARYING_COMPONENTS, Type.INTEGER), + new Limit("Max TF Varying Length", GLES30.GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, Type.INTEGER), + new Limit("Max TF Separate Components", GLES30.GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, Type.INTEGER), + new Limit("Max TF Interleaved Components", GLES30.GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, Type.INTEGER), + new Limit("Max TF Separate Attributes", GLES30.GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, Type.INTEGER), + new Limit("Max Color Attachments", GLES30.GL_MAX_COLOR_ATTACHMENTS, Type.INTEGER), + new Limit("Max Samples", GLES30.GL_MAX_SAMPLES, Type.INTEGER), + new Limit("Max Vertex UBOs", GLES30.GL_MAX_VERTEX_UNIFORM_BLOCKS, Type.INTEGER), + new Limit("Max Fragment UBOs", GLES30.GL_MAX_FRAGMENT_UNIFORM_BLOCKS, Type.INTEGER), + new Limit("Max Combined UBOs", GLES30.GL_MAX_COMBINED_UNIFORM_BLOCKS, Type.INTEGER), + new Limit("Max Uniform Buffer Bindings", GLES30.GL_MAX_UNIFORM_BUFFER_BINDINGS, Type.INTEGER), + new Limit("Max UBO Size", GLES30.GL_MAX_UNIFORM_BLOCK_SIZE, Type.INTEGER), + new Limit("Max Combined Vertex Uniform Components", GLES30.GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, Type.INTEGER), + new Limit("Max Combined Fragment Uniform Components", GLES30.GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, Type.INTEGER), + new Limit("UBO Alignment", GLES30.GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, Type.INTEGER), + new Limit("Max Vertex Output Components", GLES30.GL_MAX_VERTEX_OUTPUT_COMPONENTS, Type.INTEGER), + new Limit("Max Fragment Input Components", GLES30.GL_MAX_FRAGMENT_INPUT_COMPONENTS, Type.INTEGER), + new Limit("Max Server Wait Timeout", GLES30.GL_MAX_SERVER_WAIT_TIMEOUT, Type.INTEGER), + new Limit("Program Binary Formats", GLES30.GL_NUM_PROGRAM_BINARY_FORMATS, Type.INTEGER), + new Limit("Max Element Index", GLES30.GL_MAX_ELEMENT_INDEX, Type.INTEGER), + new Limit("Sample Counts", GLES30.GL_NUM_SAMPLE_COUNTS, Type.INTEGER), + }; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) + { + ListView rootView = (ListView) inflater.inflate(R.layout.gamelist_listview, container, false); + List Input = new ArrayList(); + + for (Limit limit : Limits) + { + Log.i("GLES3InfoFragment", "Getting enum " + limit.name); + Input.add(new AboutActivity.AboutFragmentItem(limit.name, limit.GetValue(eglHelper))); + } + + // Get extensions manually + int numExtensions = eglHelper.glGetInteger(GLES30.GL_NUM_EXTENSIONS); + StringBuilder extensionsBuilder = new StringBuilder(); + for (int i = 0; i < numExtensions; i++) + { + extensionsBuilder.append(eglHelper.glGetStringi(GLES30.GL_EXTENSIONS, i)).append('\n'); + } + Input.add(new AboutActivity.AboutFragmentItem("OpenGL ES 3.0 Extensions", extensionsBuilder.toString())); + + AboutActivity.InfoFragmentAdapter adapter = new AboutActivity.InfoFragmentAdapter(getActivity(), R.layout.about_layout, Input); + rootView.setAdapter(adapter); + + return rootView; + } +} diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/about/GLInfoFragment.java b/Source/Android/src/org/dolphinemu/dolphinemu/about/GLInfoFragment.java new file mode 100644 index 0000000000..a3d7167528 --- /dev/null +++ b/Source/Android/src/org/dolphinemu/dolphinemu/about/GLInfoFragment.java @@ -0,0 +1,69 @@ +/** + * Copyright 2013 Dolphin Emulator Project + * Licensed under GPLv2 + * Refer to the license.txt file included. + */ + +package org.dolphinemu.dolphinemu.about; + +import android.app.ListFragment; +import android.opengl.GLES20; +import android.opengl.GLES30; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.about.Limit.Type; +import org.dolphinemu.dolphinemu.utils.EGLHelper; + +import java.util.ArrayList; +import java.util.List; + +import javax.microedition.khronos.opengles.GL10; + +/** + * {@link ListFragment} responsible for displaying + * information relating to OpenGL. + */ +public final class GLInfoFragment extends ListFragment +{ + private final EGLHelper eglHelper = new EGLHelper(EGLHelper.EGL_OPENGL_BIT); + + private final Limit[] Limits = { + new Limit("Vendor", GL10.GL_VENDOR, Type.STRING), + new Limit("Version", GL10.GL_VERSION, Type.STRING), + new Limit("Renderer", GL10.GL_RENDERER, Type.STRING), + new Limit("GLSL version", GLES20.GL_SHADING_LANGUAGE_VERSION, Type.STRING), + }; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) + { + ListView rootView = (ListView) inflater.inflate(R.layout.gamelist_listview, container, false); + List Input = new ArrayList(); + + for (Limit limit : Limits) + { + Log.i("GLInfoFragment", "Getting enum " + limit.name); + Input.add(new AboutActivity.AboutFragmentItem(limit.name, limit.GetValue(eglHelper))); + } + + // Get extensions manually + int numExtensions = eglHelper.glGetInteger(GLES30.GL_NUM_EXTENSIONS); + StringBuilder extensionsBuilder = new StringBuilder(); + for (int i = 0; i < numExtensions; i++) + { + extensionsBuilder.append(eglHelper.glGetStringi(GL10.GL_EXTENSIONS, i)).append('\n'); + } + Input.add(new AboutActivity.AboutFragmentItem("OpenGL Extensions", extensionsBuilder.toString())); + + AboutActivity.InfoFragmentAdapter adapter = new AboutActivity.InfoFragmentAdapter(getActivity(), R.layout.about_layout, Input); + rootView.setAdapter(adapter); + + return rootView; + } +} diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/about/Limit.java b/Source/Android/src/org/dolphinemu/dolphinemu/about/Limit.java new file mode 100644 index 0000000000..96b206b837 --- /dev/null +++ b/Source/Android/src/org/dolphinemu/dolphinemu/about/Limit.java @@ -0,0 +1,65 @@ +package org.dolphinemu.dolphinemu.about; + +import org.dolphinemu.dolphinemu.utils.EGLHelper; + +final class Limit +{ + /** + * Possible types a Limit can be. + */ + enum Type + { + /** Generic string */ + STRING, + /** Integer constant */ + INTEGER, + /** Range of integers */ + INTEGER_RANGE, + } + + /** Name of this limit */ + public final String name; + /** The GL constant that represents this limit.*/ + public final int glEnum; + /** The {@link Type} of this limit. */ + public final Type type; + + /** + * Constructor + * + * @param name Name of the limit. + * @param glEnum The GL constant that represents this limit. + * @param type The {@link Type} of this limit. + */ + public Limit(String name, int glEnum, Type type) + { + this.name = name; + this.glEnum = glEnum; + this.type = type; + } + + /** + * Retrieves the information represented by this limit. + * + * @param context {@link EGLHelper} context to retrieve the limit with. + * + * @return the information represented by this limit. + */ + public String GetValue(EGLHelper context) + { + if (type == Type.INTEGER) + { + return Integer.toString(context.glGetInteger(glEnum)); + } + else if (type == Type.INTEGER_RANGE) + { + int[] data = new int[2]; + context.getGL().glGetIntegerv(glEnum, data, 0); + + return String.format("[%d, %d]", data[0], data[1]); + } + + // If neither of the above type, assume it's a string. + return context.glGetString(glEnum); + } +} \ No newline at end of file diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/emulation/EmulationActivity.java b/Source/Android/src/org/dolphinemu/dolphinemu/emulation/EmulationActivity.java index f04bf77e4e..7f6896536c 100644 --- a/Source/Android/src/org/dolphinemu/dolphinemu/emulation/EmulationActivity.java +++ b/Source/Android/src/org/dolphinemu/dolphinemu/emulation/EmulationActivity.java @@ -22,10 +22,12 @@ import android.view.WindowManager.LayoutParams; import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.settings.input.InputConfigFragment; -import org.dolphinemu.dolphinemu.settings.video.VideoSettingsFragment; +import org.dolphinemu.dolphinemu.utils.EGLHelper; import java.util.List; +import javax.microedition.khronos.opengles.GL10; + /** * This is the activity where all of the emulation handling happens. * This activity is responsible for displaying the SurfaceView that we render to. @@ -65,11 +67,7 @@ public final class EmulationActivity extends Activity // 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_QualcommVersion < 53.0f) + if (hasBuggedDriverDimensions()) NativeLibrary.SetDimensions((int)screenHeight, (int)screenWidth); else NativeLibrary.SetDimensions((int)screenWidth, (int)screenHeight); @@ -330,4 +328,39 @@ public final class EmulationActivity extends Activity return true; } + + // For handling bugged driver dimensions (applies mainly to Qualcomm devices) + private boolean hasBuggedDriverDimensions() + { + final EGLHelper eglHelper = new EGLHelper(EGLHelper.EGL_OPENGL_ES2_BIT); + final String vendor = eglHelper.getGL().glGetString(GL10.GL_VENDOR); + final String version = eglHelper.getGL().glGetString(GL10.GL_VERSION); + final String renderer = eglHelper.getGL().glGetString(GL10.GL_RENDERER); + + if (sharedPrefs.getString("gpuPref", "Software Rendering").equals("OGL") + && eglHelper.supportsGLES3() + && vendor.equals("Qualcomm") + && renderer.equals("Adreno (TM) 3")) + { + final int start = version.indexOf("V@") + 2; + final StringBuilder versionBuilder = new StringBuilder(); + + for (int i = start; i < version.length(); i++) + { + char c = version.charAt(i); + + // End of numeric portion of version string. + if (c == ' ') + break; + + versionBuilder.append(c); + } + + if (Float.parseFloat(versionBuilder.toString()) < 53.0f) + return true; + } + + + return false; + } } diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/gamelist/GameListActivity.java b/Source/Android/src/org/dolphinemu/dolphinemu/gamelist/GameListActivity.java index 85fa9a62da..6a5f806da4 100644 --- a/Source/Android/src/org/dolphinemu/dolphinemu/gamelist/GameListActivity.java +++ b/Source/Android/src/org/dolphinemu/dolphinemu/gamelist/GameListActivity.java @@ -23,9 +23,10 @@ import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; -import org.dolphinemu.dolphinemu.AboutFragment; + import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.about.AboutActivity; import org.dolphinemu.dolphinemu.folderbrowser.FolderBrowser; import org.dolphinemu.dolphinemu.settings.PrefsActivity; import org.dolphinemu.dolphinemu.sidemenu.SideMenuAdapter; @@ -119,11 +120,7 @@ public final class GameListActivity extends Activity 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.setPositiveButton(R.string.yes, null); builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { @@ -184,13 +181,8 @@ public final class GameListActivity extends Activity case 3: // About { - mCurFragmentNum = 3; - final AboutFragment aboutFragment = new AboutFragment(); - FragmentTransaction ft = getFragmentManager().beginTransaction(); - ft.replace(R.id.content_frame, aboutFragment); - ft.addToBackStack(null); - ft.commit(); - invalidateOptionsMenu(); + Intent intent = new Intent(this, AboutActivity.class); + startActivity(intent); } break; @@ -261,7 +253,8 @@ public final class GameListActivity extends Activity AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.clear_game_list); builder.setMessage(getString(R.string.clear_game_list_confirm)); - builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener(){ + builder.setNegativeButton(R.string.no, null); + builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { String directories = NativeLibrary.GetConfig("Dolphin.ini", "General", "GCMPathes", "0"); @@ -279,12 +272,6 @@ public final class GameListActivity extends Activity ((GameListFragment) getFragmentManager().findFragmentById(R.id.content_frame)).clearGameList(); } }); - builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) - { - // Do nothing. This just make "No" appear. - } - }); builder.show(); } diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/settings/PrefsActivity.java b/Source/Android/src/org/dolphinemu/dolphinemu/settings/PrefsActivity.java index 5368475319..41979ece46 100644 --- a/Source/Android/src/org/dolphinemu/dolphinemu/settings/PrefsActivity.java +++ b/Source/Android/src/org/dolphinemu/dolphinemu/settings/PrefsActivity.java @@ -41,7 +41,7 @@ public final class PrefsActivity extends Activity implements ActionBar.TabListen super.onCreate(savedInstanceState); // Set the ViewPager. - setContentView(R.layout.prefs_viewpager); + setContentView(R.layout.viewpager); mViewPager = (ViewPager) findViewById(R.id.pager); // Set the ViewPager adapter. diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/settings/video/VideoSettingsFragment.java b/Source/Android/src/org/dolphinemu/dolphinemu/settings/video/VideoSettingsFragment.java index f36a7d3ec7..55c1eb8963 100644 --- a/Source/Android/src/org/dolphinemu/dolphinemu/settings/video/VideoSettingsFragment.java +++ b/Source/Android/src/org/dolphinemu/dolphinemu/settings/video/VideoSettingsFragment.java @@ -15,9 +15,10 @@ import android.preference.ListPreference; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; import android.preference.PreferenceScreen; -import org.dolphinemu.dolphinemu.R; -import javax.microedition.khronos.egl.*; +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.utils.EGLHelper; + import javax.microedition.khronos.opengles.GL10; /** @@ -25,173 +26,9 @@ import javax.microedition.khronos.opengles.GL10; */ public final class VideoSettingsFragment extends PreferenceFragment { - public static String m_GLVersion; - public static String m_GLVendor; - public static String m_GLRenderer; - public static String m_GLExtensions; - public static boolean m_SupportsGLES3 = false; - public static float m_QualcommVersion; - public static boolean m_Inited = false; - - /** - * Class which provides a means to retrieve various - * info about the OpenGL ES support/features within a device. - */ - public static final class VersionCheck - { - private EGL10 mEGL; - private EGLDisplay mEGLDisplay; - private EGLConfig[] mEGLConfigs; - private EGLConfig mEGLConfig; - private EGLContext mEGLContext; - private EGLSurface mEGLSurface; - private GL10 mGL; - - String mThreadOwner; - - public VersionCheck() - { - int[] version = new int[2]; - int[] attribList = new int[] { - EGL10.EGL_WIDTH, 1, - EGL10.EGL_HEIGHT, 1, - EGL10.EGL_RENDERABLE_TYPE, 4, - EGL10.EGL_NONE - }; - int EGL_CONTEXT_CLIENT_VERSION = 0x3098; - int[] ctx_attribs = new int[] { - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL10.EGL_NONE - }; - - // No error checking performed, minimum required code to elucidate logic - mEGL = (EGL10) EGLContext.getEGL(); - mEGLDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); - mEGL.eglInitialize(mEGLDisplay, version); - mEGLConfig = chooseConfig(); // Choosing a config is a little more complicated - mEGLContext = mEGL.eglCreateContext(mEGLDisplay, mEGLConfig, EGL10.EGL_NO_CONTEXT, ctx_attribs); - mEGLSurface = mEGL.eglCreatePbufferSurface(mEGLDisplay, mEGLConfig, attribList); - mEGL.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext); - mGL = (GL10) mEGLContext.getGL(); - - // Record thread owner of OpenGL context - mThreadOwner = Thread.currentThread().getName(); - } - - /** - * Gets the OpenGL ES version string. - * - * @return the OpenGL ES version string. - */ - public String getVersion() - { - return mGL.glGetString(GL10.GL_VERSION); - } - - /** - * Gets the OpenGL ES vendor string. - * - * @return the OpenGL ES vendor string. - */ - public String getVendor() - { - return mGL.glGetString(GL10.GL_VENDOR); - } - - /** - * Gets the name of the OpenGL ES renderer. - * - * @return the name of the OpenGL ES renderer. - */ - public String getRenderer() - { - return mGL.glGetString(GL10.GL_RENDERER); - } - - /** - * Gets the extension that the device supports - * - * @return String containing the extensions - */ - public String getExtensions() - { - return mGL.glGetString(GL10.GL_EXTENSIONS); - } - - private EGLConfig chooseConfig() - { - int[] attribList = new int[] { - EGL10.EGL_RED_SIZE, 8, - EGL10.EGL_GREEN_SIZE, 8, - EGL10.EGL_BLUE_SIZE, 8, - EGL10.EGL_ALPHA_SIZE, 8, - EGL10.EGL_NONE - }; - - // Grab how many configs there are - int[] numConfig = new int[1]; - mEGL.eglChooseConfig(mEGLDisplay, attribList, null, 0, numConfig); - int configSize = numConfig[0]; - mEGLConfigs = new EGLConfig[configSize]; - mEGL.eglChooseConfig(mEGLDisplay, attribList, mEGLConfigs, configSize, numConfig); - - // Check if one config supports GLES3 - for (int i = 0; i < configSize; ++i) - { - int[] value = new int[1]; - boolean retval = mEGL.eglGetConfigAttrib(mEGLDisplay, mEGLConfigs[i], EGL10.EGL_RENDERABLE_TYPE, value); - if (retval && (value[0] & (1 << 6)) != 0) - { - m_SupportsGLES3 = true; - break; - } - } - - return mEGLConfigs[0]; // Best match is probably the first configuration - } - } - - /** - * Checks if this device supports OpenGL ES 3. - * - * @return true if this device supports OpenGL ES 3; false otherwise. - */ - public static boolean SupportsGLES3() - { - if (!m_Inited) - { - VersionCheck mbuffer = new VersionCheck(); - m_GLVersion = mbuffer.getVersion(); - m_GLVendor = mbuffer.getVendor(); - m_GLRenderer = mbuffer.getRenderer(); - m_GLExtensions = mbuffer.getExtensions(); - - // Checking for OpenGL ES 3 support for certain Qualcomm devices. - if (m_GLVendor != null && m_GLVendor.equals("Qualcomm")) - { - if (m_GLRenderer.contains("Adreno (TM) 3")) - { - int mVStart = m_GLVersion.indexOf("V@") + 2; - int mVEnd = 0; - - for (int a = mVStart; a < m_GLVersion.length(); ++a) - { - if (m_GLVersion.charAt(a) == ' ') - { - mVEnd = a; - break; - } - } - - m_QualcommVersion = Float.parseFloat(m_GLVersion.substring(mVStart, mVEnd)); - } - } - - m_Inited = true; - } - - return m_SupportsGLES3; - } + private final EGLHelper eglHelper = new EGLHelper(EGLHelper.EGL_OPENGL_ES2_BIT); + private final String vendor = eglHelper.getGL().glGetString(GL10.GL_VENDOR); + private final String version = eglHelper.getGL().glGetString(GL10.GL_VERSION); @Override public void onCreate(Bundle savedInstanceState) @@ -205,7 +42,7 @@ public final class VideoSettingsFragment extends PreferenceFragment // Setting valid video backends. // final ListPreference videoBackends = (ListPreference) findPreference("gpuPref"); - final boolean deviceSupportsGLES3 = SupportsGLES3(); + final boolean deviceSupportsGLES3 = eglHelper.supportsGLES3(); if (deviceSupportsGLES3) { @@ -264,10 +101,9 @@ public final class VideoSettingsFragment extends PreferenceFragment //mainScreen.getPreference(4).setEnabled(false); // Create an alert telling them that their phone sucks - if (VideoSettingsFragment.SupportsGLES3() - && VideoSettingsFragment.m_GLVendor != null - && VideoSettingsFragment.m_GLVendor.equals("Qualcomm") - && VideoSettingsFragment.m_QualcommVersion == 14.0f) + if (eglHelper.supportsGLES3() + && vendor.equals("Qualcomm") + && getQualcommVersion() == 14.0f) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setTitle(R.string.device_compat_warning); @@ -295,4 +131,23 @@ public final class VideoSettingsFragment extends PreferenceFragment } }); } + + private float getQualcommVersion() + { + final int start = version.indexOf("V@") + 2; + final StringBuilder versionBuilder = new StringBuilder(); + + for (int i = start; i < version.length(); i++) + { + char c = version.charAt(i); + + // End of numeric portion of version string. + if (c == ' ') + break; + + versionBuilder.append(c); + } + + return Float.parseFloat(versionBuilder.toString()); + } } diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/utils/CPUHelper.java b/Source/Android/src/org/dolphinemu/dolphinemu/utils/CPUHelper.java new file mode 100644 index 0000000000..43e6b66da4 --- /dev/null +++ b/Source/Android/src/org/dolphinemu/dolphinemu/utils/CPUHelper.java @@ -0,0 +1,400 @@ +package org.dolphinemu.dolphinemu.utils; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +import org.dolphinemu.dolphinemu.R; + +import android.content.Context; +import android.os.Build; +import android.util.Log; + +/** + * Utility class for retrieving information + * from a device's CPU. + */ +public final class CPUHelper +{ + private int revision; + private int architecture; + private int variant; + private int numCores; + private String implementerID = "N/A"; + private String part = "N/A"; + private String hardware = "N/A"; + private String processorInfo = "N/A"; + private String features = "N/A"; + + private final Context ctx; + + /** + * Constructor + * + * @param ctx The current {@link Context}. + */ + public CPUHelper(Context ctx) + { + this.ctx = ctx; + + try + { + // TODO: Should do other architectures as well (x86 and MIPS). + // Can do differentiating between platforms by using + // android.os.Build.CPU_ABI. + // + // CPU_ABI.contains("armeabi") == get ARM info. + // CPU_ABI.contains("x86") == get x86 info. + // CPU_ABI.contains("mips") == get MIPS info. + // + // However additional testing should be done across devices, + // I highly doubt /proc/cpuinfo retains the same formatting + // on different architectures. + // + // If push comes to shove, we can simply spit out the cpuinfo + // contents. I would like to avoid this if possible, however. + + if (Build.CPU_ABI.contains("arm")) + { + getARMInfo(); + } + else + { + Log.e("CPUHelper", "CPU architecture not supported yet."); + } + } + catch (IOException ioe) + { + Log.e("CPUHelper", ioe.getMessage()); + } + } + + /** + * Gets the revision number of the CPU. + * + * @return the revision number of the CPU. + */ + public int getRevision() + { + return revision; + } + + /** + * Gets the architecture number of the CPU. + * + * @return the architecture number of the CPU. + */ + public int getArchitecture() + { + return architecture; + } + + /** + * Gets the CPU variant number. + * + * @return the CPU variant number. + */ + public int getVariant() + { + return variant; + } + + /** + * Gets the total number of cores in the CPU. + * + * @return the total number of cores in the CPU. + */ + public int getNumCores() + { + return numCores; + } + + /** + * Gets the name of the implementer of the CPU. + * + * @return the name of the implementer of the CPU. + */ + public String getImplementer() + { + return implementerID; + } + + /** + * Gets the specific processor type of the CPU. + * + * @return the specific processor type. + */ + public String getProcessorType() + { + return part; + } + + /** + * Gets the internal name of the hardware. + * + * @return the internal name of the hardware. + */ + public String getHardware() + { + return hardware; + } + + /** + * Get the processor info string. + * + * @return the processor info string. + */ + public String getProcessorInfo() + { + return processorInfo; + } + + /** + * Gets the features supported by the CPU. + * + * @return the features supported by the CPU. + */ + public String getFeatures() + { + return features; + } + + /** + * Whether or not this CPU is using the ARM architecture. + * + * @return true if this CPU uses the ARM architecture; false otherwise. + */ + public static boolean isARM() + { + return Build.CPU_ABI.contains("arm"); + } + + /** + * Whether or not this CPU is using the x86 architecture. + * + * @return true if this CPU uses the x86 architecture; false otherwise. + */ + public static boolean isX86() + { + return Build.CPU_ABI.contains("x86"); + } + + /** + * Whether or not this CPU is using the MIPS architecture. + * + * @return true if this CPU uses the MIPS architecture; false otherwise. + */ + public static boolean isMIPS() + { + return Build.CPU_ABI.contains("mips"); + } + + // Retrieves information for ARM CPUs. + private void getARMInfo() throws IOException + { + File info = new File("/proc/cpuinfo"); + if (info.exists()) + { + BufferedReader br = new BufferedReader(new FileReader(info)); + + String line; + while ((line = br.readLine()) != null) + { + if (line.contains("Processor\t:")) + { + this.processorInfo = parseLine(line); + } + else if (line.contains("Hardware\t:")) + { + this.hardware = parseLine(line); + } + else if (line.contains("Features\t:")) + { + this.features = parseLine(line); + } + else if (line.contains("CPU implementer\t:")) + { + this.implementerID = parseArmID(Integer.decode(parseLine(line))); + } + // Intentional lack of "\t:" sometimes the tab isn't present. + else if (line.contains("CPU architecture")) + { + this.architecture = Integer.decode(parseLine(line)); + } + else if (line.contains("CPU part\t:")) + { + this.part = parseArmPartNumber(Integer.decode(parseLine(line))); + } + else if (line.contains("CPU revision\t:")) + { + this.revision = Integer.decode(parseLine(line)); + } + else if (line.contains("CPU variant\t:")) + { + this.variant = Integer.decode(parseLine(line)); + } + else if (line.contains("processor\t:")) // Lower case indicates a specific core number + { + this.numCores++; + } + } + + br.close(); + } + } + + // Basic function for parsing cpuinfo format strings. + // cpuinfo format strings consist of [label:info] parts. + // We only want to retrieve the info portion so we split + // them using ':' as a delimeter. + private String parseLine(String line) + { + String[] temp = line.split(":"); + if (temp.length != 2) + return "N/A"; + + return temp[1].trim(); + } + + // Parses an ARM CPU ID. + private String parseArmID(int id) + { + switch (id) + { + case 0x41: + return "ARM Limited"; + + case 0x44: + return "Digital Equipment Corporation"; + + case 0x4D: + return "Freescale Semiconductor Inc."; + + case 0x51: + return "Qualcomm Inc."; + + case 0x56: + return "Marvell Semiconductor Inc."; + + case 0x69: + return "Intel Corporation"; + + default: + return "N/A"; + } + } + + // Parses the ARM CPU Part number. + private String parseArmPartNumber(int partNum) + { + switch (partNum) + { + // Qualcomm part numbers. + case 0x00F: + return "Qualcomm Scorpion"; + + case 0x02D: + return "Qualcomm Dual Scorpion"; + + case 0x04D: + return "Qualcomm Dual Krait"; + + case 0x06F: + return "Qualcomm Quad Krait"; + + // Marvell Semiconductor part numbers + case 0x131: + return "Marvell Feroceon"; + + case 0x581: + return "Marvell PJ4/PJ4b"; + + case 0x584: + return "Marvell Dual PJ4/PJ4b"; + + // Official ARM part numbers. + case 0x920: + return "ARM920"; + + case 0x922: + return "ARM922"; + + case 0x926: + return "ARM926"; + + case 0x940: + return "ARM940"; + + case 0x946: + return "ARM946"; + + case 0x966: + return "ARM966"; + + case 0x968: + return "ARM968"; + + case 0xB02: + return "ARM11 MPCore"; + + case 0xB36: + return "ARM1136"; + + case 0xB56: + return "ARM1156"; + + case 0xB76: + return "ARM1176"; + + case 0xC05: + return "ARM Cortex A5"; + + case 0xC07: + return "ARM Cortex-A7 MPCore"; + + case 0xC08: + return "ARM Cortex A8"; + + case 0xC09: + return "ARM Cortex A9"; + + case 0xC0C: + return "ARM Cortex A12"; + + case 0xC0F: + return "ARM Cortex A15"; + + case 0xC14: + return "ARM Cortex R4"; + + case 0xC15: + return "ARM Cortex R5"; + + case 0xC20: + return "ARM Cortex M0"; + + case 0xC21: + return "ARM Cortex M1"; + + case 0xC23: + return "ARM Cortex M3"; + + case 0xC24: + return "ARM Cortex M4"; + + case 0xC60: + return "ARM Cortex M0+"; + + case 0xD03: + return "ARM Cortex A53"; + + case 0xD07: + return "ARM Cortex A57 MPCore"; + + + default: // Unknown/Not yet added to list. + return String.format(ctx.getString(R.string.unknown_part_num), partNum); + } + } +} diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/utils/EGLHelper.java b/Source/Android/src/org/dolphinemu/dolphinemu/utils/EGLHelper.java new file mode 100644 index 0000000000..94ea903ae6 --- /dev/null +++ b/Source/Android/src/org/dolphinemu/dolphinemu/utils/EGLHelper.java @@ -0,0 +1,360 @@ +/** + * Copyright 2013 Dolphin Emulator Project + * Licensed under GPLv2 + * Refer to the license.txt file included. + */ + +package org.dolphinemu.dolphinemu.utils; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.egl.EGLSurface; +import javax.microedition.khronos.opengles.GL10; + +import android.opengl.GLES30; +import android.util.Log; + +/** + * Utility class that abstracts all the stuff about + * EGL initialization out of the way if all that is + * wanted is to query the underlying GL API for information. + */ +public final class EGLHelper +{ + private final EGL10 mEGL; + private final EGLDisplay mDisplay; + private EGLConfig[] mEGLConfigs; + private EGLContext mEGLContext; + private EGLSurface mEGLSurface; + private GL10 mGL; + + // GL support flags + private boolean supportGL; + private boolean supportGLES2; + private boolean supportGLES3; + + // Renderable type bitmasks + public static final int EGL_OPENGL_ES_BIT = 0x0001; + public static final int EGL_OPENGL_ES2_BIT = 0x0004; + public static final int EGL_OPENGL_BIT = 0x0008; + public static final int EGL_OPENGL_ES3_BIT_KHR = 0x0040; + + /** + * Constructor + *

+ * Initializes the underlying {@link EGLSurface} with a width and height of 1. + * This is useful if all you need to use this class for is to query information + * from specific API contexts. + * + * @param renderableType Bitmask indicating which types of client API contexts + * the framebuffer config must support. + */ + public EGLHelper(int renderableType) + { + this(1, 1, renderableType); + } + + /** + * Constructor + * + * @param width Width of the underlying {@link EGLSurface}. + * @param height Height of the underlying {@link EGLSurface}. + * @param renderableType Bitmask indicating which types of client API contexts + * the framebuffer config must support. + */ + public EGLHelper(int width, int height, int renderableType) + { + // Initialize handle to an EGL display. + mEGL = (EGL10) EGLContext.getEGL(); + mDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + + // If a display is present, initialize EGL. + if (mDisplay != EGL10.EGL_NO_DISPLAY) + { + int[] version = new int[2]; + if (mEGL.eglInitialize(mDisplay, version)) + { + // Detect supported GL APIs, initialize configs, etc. + detect(); + + // Create context and surface + create(width, height, renderableType); + } + else + { + Log.e("EGLHelper", "Error initializing EGL."); + } + } + else + { + Log.e("EGLHelper", "Error initializing EGL display."); + } + } + + /** + * Releases all resources associated with this helper. + *

+ * This should be called whenever this helper is no longer needed. + */ + public void closeHelper() + { + mEGL.eglTerminate(mDisplay); + } + + /** + * Gets information through EGL.
+ *

+ * Index 0: Vendor
+ * Index 1: Version
+ * Index 2: Renderer
+ * Index 3: Extensions
+ * + * @return information retrieved through EGL. + */ + public String[] getEGLInfo() + { + String[] info = { + mGL.glGetString(GL10.GL_VENDOR), + mGL.glGetString(GL10.GL_VERSION), + mGL.glGetString(GL10.GL_RENDERER), + mGL.glGetString(GL10.GL_EXTENSIONS), + }; + + return info; + } + + /** + * Whether or not this device supports OpenGL. + * + * @return true if this device supports OpenGL; false otherwise. + */ + public boolean supportsOpenGL() + { + return supportGL; + } + + /** + * Whether or not this device supports OpenGL ES 2. + *
+ * Note that if this returns true, then OpenGL ES 1 is also supported. + * + * @return true if this device supports OpenGL ES 2; false otherwise. + */ + public boolean supportsGLES2() + { + return supportGLES2; + } + + /** + * Whether or not this device supports OpenGL ES 3. + *
+ * Note that if this returns true, then OpenGL ES 1 and 2 are also supported. + * + * @return true if this device supports OpenGL ES 3; false otherwise. + */ + public boolean supportsGLES3() + { + return supportGLES3; + } + + /** + * Gets the underlying {@link EGL10} instance. + * + * @return the underlying {@link EGL10} instance. + */ + public EGL10 getEGL() + { + return mEGL; + } + + /** + * Gets the underlying {@link GL10} instance. + * + * @return the underlying {@link GL10} instance. + */ + public GL10 getGL() + { + return mGL; + } + + /** + * Gets the underlying {@link EGLDisplay}. + * + * @return the underlying {@link EGLDisplay} + */ + public EGLDisplay getDisplay() + { + return mDisplay; + } + + /** + * Gets all supported framebuffer configurations for this device. + * + * @return all supported framebuffer configurations for this device. + */ + public EGLConfig[] getConfigs() + { + return mEGLConfigs; + } + + /** + * Gets the underlying {@link EGLContext}. + * + * @return the underlying {@link EGLContext}. + */ + public EGLContext getContext() + { + return mEGLContext; + } + + /** + * Gets the underlying {@link EGLSurface}. + * + * @return the underlying {@link EGLSurface}. + */ + public EGLSurface getSurface() + { + return mEGLSurface; + } + + // Detects the specific kind of GL modes that are supported + private boolean detect() + { + // Get total number of configs available. + int[] numConfigs = new int[1]; + if (!mEGL.eglGetConfigs(mDisplay, null, 0, numConfigs)) + { + Log.e("EGLHelper", "Error retrieving number of EGL configs available."); + return false; + } + + // Now get all the configurations + mEGLConfigs = new EGLConfig[numConfigs[0]]; + if (!mEGL.eglGetConfigs(mDisplay, mEGLConfigs, mEGLConfigs.length, numConfigs)) + { + Log.e("EGLHelper", "Error retrieving all EGL configs."); + return false; + } + + for (int i = 0; i < mEGLConfigs.length; i++) + { + int[] attribVal = new int[1]; + boolean ret = mEGL.eglGetConfigAttrib(mDisplay, mEGLConfigs[i], EGL10.EGL_RENDERABLE_TYPE, attribVal); + if (ret) + { + if ((attribVal[0] & EGL_OPENGL_BIT) != 0) + supportGL = true; + + if ((attribVal[0] & EGL_OPENGL_ES2_BIT) != 0) + supportGLES2 = true; + + if ((attribVal[0] & EGL_OPENGL_ES3_BIT_KHR) != 0) + supportGLES3 = true; + } + } + + return true; + } + + // Creates the context and surface. + private void create(int width, int height, int renderableType) + { + int[] attribs = { + EGL10.EGL_WIDTH, width, + EGL10.EGL_HEIGHT, height, + EGL10.EGL_NONE + }; + + // Initially we just assume GLES2 will be the default context. + int EGL_CONTEXT_CLIENT_VERSION = 0x3098; + int[] ctx_attribs = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL10.EGL_NONE + }; + + // Determine the type of context that will be created + // and change the attribute arrays accordingly. + switch (renderableType) + { + case EGL_OPENGL_ES_BIT: + ctx_attribs[1] = 1; + break; + + case EGL_OPENGL_BIT: + ctx_attribs[0] = EGL10.EGL_NONE; + break; + + case EGL_OPENGL_ES3_BIT_KHR: + ctx_attribs[1] = 3; + break; + + case EGL_OPENGL_ES2_BIT: + default: // Fall-back to GLES 2. + ctx_attribs[1] = 2; + break; + } + + mEGLContext = mEGL.eglCreateContext(mDisplay, mEGLConfigs[0], EGL10.EGL_NO_CONTEXT, ctx_attribs); + mEGLSurface = mEGL.eglCreatePbufferSurface(mDisplay, mEGLConfigs[0], attribs); + mEGL.eglMakeCurrent(mDisplay, mEGLSurface, mEGLSurface, mEGLContext); + mGL = (GL10) mEGLContext.getGL(); + } + + /** + * Simplified call to {@link GL10#glGetString(int)} + *

+ * Accepts the following constants: + *

    + *
  • GL_VENDOR - Company responsible for the GL implementation.
  • + *
  • GL_VERSION - Version or release number.
  • + *
  • GL_RENDERER - Name of the renderer
  • + *
  • GL_SHADING_LANGUAGE_VERSION - Version or release number of the shading language
  • + *
+ * + * @param glEnum A symbolic constant within {@link GL10}. + * + * @return the string information represented by {@code glEnum}. + */ + public String glGetString(int glEnum) + { + return mGL.glGetString(glEnum); + } + + /** + * Simplified call to {@link GLES30#glGetStringi(int, int)} + *

+ * Accepts the following constants: + *

    + *
  • GL_VENDOR - Company responsible for the GL implementation.
  • + *
  • GL_VERSION - Version or release number.
  • + *
  • GL_RENDERER - Name of the renderer
  • + *
  • GL_SHADING_LANGUAGE_VERSION - Version or release number of the shading language
  • + *
  • GL_EXTENSIONS - Extension string supported by the implementation at {@code index}.
  • + *
+ * + * @param glEnum A symbolic GL constant + * @param index The index of the string to return. + * + * @return the string information represented by {@code glEnum} and {@code index}. + */ + public String glGetStringi(int glEnum, int index) + { + return GLES30.glGetStringi(glEnum, index); + } + + /** + * Simplified call to {@link GL10#glGetIntegerv(int, int[], int) + * + * @param glEnum A symbolic GL constant. + * + * @return the integer information represented by {@code glEnum}. + */ + public int glGetInteger(int glEnum) + { + int[] val = new int[1]; + mGL.glGetIntegerv(glEnum, val, 0); + return val[0]; + } +}