mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-08 20:16:27 +02:00
Merge pull request #8274 from hrydgard/android-native-egl
Initialize OpenGL from C++ using EGL on Android
This commit is contained in:
commit
99fe0981ee
20 files changed
+1057
-697
No files matched your search
+35
-4
@@ -72,7 +72,7 @@
|
||||
<PreprocessorDefinitions>USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_32=1;_M_IX86=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>../ext/native</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>../ext/native;..</AdditionalIncludeDirectories>
|
||||
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
@@ -99,7 +99,7 @@
|
||||
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PreprocessorDefinitions>USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;_M_X64=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../ext/native</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>../ext/native;..</AdditionalIncludeDirectories>
|
||||
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
@@ -132,7 +132,7 @@
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
<AdditionalIncludeDirectories>../ext/native</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>../ext/native;..</AdditionalIncludeDirectories>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
@@ -161,7 +161,7 @@
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;_M_X64=1;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
||||
<AdditionalIncludeDirectories>../ext/native</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>../ext/native;..</AdditionalIncludeDirectories>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
@@ -209,6 +209,19 @@
|
||||
<ClInclude Include="Crypto\sha256.h" />
|
||||
<ClInclude Include="FileUtil.h" />
|
||||
<ClInclude Include="FixedSizeQueue.h" />
|
||||
<ClInclude Include="GL\GLInterfaceBase.h" />
|
||||
<ClInclude Include="GL\GLInterface\EGL.h">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GL\GLInterface\EGLAndroid.h">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="KeyMap.h" />
|
||||
<ClInclude Include="Log.h" />
|
||||
<ClInclude Include="LogManager.h" />
|
||||
@@ -258,6 +271,24 @@
|
||||
<ClCompile Include="Crypto\sha1.cpp" />
|
||||
<ClCompile Include="Crypto\sha256.cpp" />
|
||||
<ClCompile Include="FileUtil.cpp" />
|
||||
<ClCompile Include="GL\GLInterface\EGL.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GL\GLInterface\EGLAndroid.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GL\GLInterface\GLInterface.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="KeyMap.cpp" />
|
||||
<ClCompile Include="LogManager.cpp" />
|
||||
<ClCompile Include="MemArena.cpp" />
|
||||
|
||||
@@ -48,6 +48,15 @@
|
||||
<ClInclude Include="ColorConv.h" />
|
||||
<ClInclude Include="ColorConvNEON.h" />
|
||||
<ClInclude Include="ThreadSafeList.h" />
|
||||
<ClInclude Include="GL\GLInterface\EGL.h">
|
||||
<Filter>GL\GLInterface</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GL\GLInterface\EGLAndroid.h">
|
||||
<Filter>GL\GLInterface</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GL\GLInterfaceBase.h">
|
||||
<Filter>GL</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp" />
|
||||
@@ -84,6 +93,15 @@
|
||||
<ClCompile Include="Arm64Emitter.cpp" />
|
||||
<ClCompile Include="ColorConv.cpp" />
|
||||
<ClCompile Include="ColorConvNEON.cpp" />
|
||||
<ClCompile Include="GL\GLInterface\EGL.cpp">
|
||||
<Filter>GL\GLInterface</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GL\GLInterface\EGLAndroid.cpp">
|
||||
<Filter>GL\GLInterface</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GL\GLInterface\GLInterface.cpp">
|
||||
<Filter>GL\GLInterface</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
@@ -92,5 +110,11 @@
|
||||
<Filter Include="Crypto">
|
||||
<UniqueIdentifier>{1b593f03-7b28-4707-9228-4981796f5589}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="GL">
|
||||
<UniqueIdentifier>{2f2ca112-9e26-499e-9cb9-38a78b4ac09d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="GL\GLInterface">
|
||||
<UniqueIdentifier>{2c723cf4-75b6-406a-90c0-ebb7a13ba476}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,324 @@
|
||||
// Copyright 2012 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "Common/GL/GLInterface/EGL.h"
|
||||
#include "Common/Log.h"
|
||||
|
||||
// Show the current FPS
|
||||
void cInterfaceEGL::Swap()
|
||||
{
|
||||
eglSwapBuffers(egl_dpy, egl_surf);
|
||||
}
|
||||
void cInterfaceEGL::SwapInterval(int Interval)
|
||||
{
|
||||
eglSwapInterval(egl_dpy, Interval);
|
||||
}
|
||||
|
||||
void* cInterfaceEGL::GetFuncAddress(const std::string& name)
|
||||
{
|
||||
return (void*)eglGetProcAddress(name.c_str());
|
||||
}
|
||||
|
||||
void cInterfaceEGL::DetectMode()
|
||||
{
|
||||
EGLint num_configs;
|
||||
bool supportsGL = false, supportsGLES2 = false, supportsGLES3 = false;
|
||||
std::array<int, 3> renderable_types = {
|
||||
EGL_OPENGL_BIT,
|
||||
(1 << 6), /* EGL_OPENGL_ES3_BIT_KHR */
|
||||
EGL_OPENGL_ES2_BIT,
|
||||
};
|
||||
|
||||
for (auto renderable_type : renderable_types)
|
||||
{
|
||||
// attributes for a visual in RGBA format with at least
|
||||
// 8 bits per color
|
||||
int attribs[] = {
|
||||
EGL_RENDERABLE_TYPE, renderable_type,
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_ALPHA_SIZE, 8,
|
||||
EGL_DEPTH_SIZE, 16,
|
||||
EGL_STENCIL_SIZE, 8,
|
||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||
EGL_TRANSPARENT_TYPE, EGL_NONE,
|
||||
EGL_SAMPLES, 0,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
// Get how many configs there are
|
||||
if (!eglChooseConfig( egl_dpy, attribs, nullptr, 0, &num_configs))
|
||||
{
|
||||
INFO_LOG(G3D, "Error: couldn't get an EGL visual config\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
EGLConfig* config = new EGLConfig[num_configs];
|
||||
|
||||
// Get all the configurations
|
||||
if (!eglChooseConfig(egl_dpy, attribs, config, num_configs, &num_configs))
|
||||
{
|
||||
INFO_LOG(G3D, "Error: couldn't get an EGL visual config\n");
|
||||
delete[] config;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_configs; ++i)
|
||||
{
|
||||
EGLint attribVal;
|
||||
bool ret;
|
||||
ret = eglGetConfigAttrib(egl_dpy, config[i], EGL_RENDERABLE_TYPE, &attribVal);
|
||||
if (ret)
|
||||
{
|
||||
if ((attribVal & EGL_OPENGL_BIT) && s_opengl_mode != GLInterfaceMode::MODE_DETECT_ES)
|
||||
supportsGL = true;
|
||||
if (attribVal & (1 << 6)) /* EGL_OPENGL_ES3_BIT_KHR */
|
||||
supportsGLES3 = true;
|
||||
if (attribVal & EGL_OPENGL_ES2_BIT)
|
||||
supportsGLES2 = true;
|
||||
}
|
||||
}
|
||||
delete[] config;
|
||||
}
|
||||
|
||||
if (supportsGL)
|
||||
s_opengl_mode = GLInterfaceMode::MODE_OPENGL;
|
||||
else if (supportsGLES3)
|
||||
s_opengl_mode = GLInterfaceMode::MODE_OPENGLES3;
|
||||
else if (supportsGLES2)
|
||||
s_opengl_mode = GLInterfaceMode::MODE_OPENGLES2;
|
||||
|
||||
if (s_opengl_mode == GLInterfaceMode::MODE_DETECT) // Errored before we found a mode
|
||||
s_opengl_mode = GLInterfaceMode::MODE_OPENGL; // Fall back to OpenGL
|
||||
}
|
||||
|
||||
static void LogEGLConfig(EGLDisplay egl_dpy, EGLConfig config) {
|
||||
EGLint red = 0, green = 0, blue = 0, alpha = 0, depth = 0, stencil = 0, format = -1, type;
|
||||
|
||||
struct {
|
||||
EGLint value;
|
||||
const char *name;
|
||||
} vals[] = {
|
||||
{ EGL_RED_SIZE, "EGL_RED_SIZE" },
|
||||
{ EGL_GREEN_SIZE, "EGL_GREEN_SIZE" },
|
||||
{ EGL_BLUE_SIZE, "EGL_BLUE_SIZE" },
|
||||
{ EGL_ALPHA_SIZE, "EGL_ALPHA_SIZE" },
|
||||
{ EGL_DEPTH_SIZE, "EGL_DEPTH_SIZE" },
|
||||
{ EGL_STENCIL_SIZE, "EGL_STENCIL_SIZE" },
|
||||
{ EGL_NATIVE_VISUAL_ID, "EGL_NATIVE_VISUAL_ID" },
|
||||
{ EGL_NATIVE_VISUAL_TYPE, "EGL_NATIVE_VISUAL_TYPE" },
|
||||
{ EGL_MAX_SWAP_INTERVAL, "EGL_MAX_SWAP_INTERVAL" },
|
||||
{ EGL_MIN_SWAP_INTERVAL, "EGL_MIN_SWAP_INTERVAL" },
|
||||
{ EGL_MIN_SWAP_INTERVAL, "EGL_MIN_SWAP_INTERVAL" },
|
||||
{ EGL_NATIVE_RENDERABLE, "EGL_NATIVE_RENDERABLE" },
|
||||
{ EGL_COLOR_BUFFER_TYPE, "EGL_COLOR_BUFFER_TYPE" },
|
||||
{ EGL_BUFFER_SIZE, "EGL_BUFFER_SIZE" },
|
||||
{ EGL_CONFIG_ID, "EGL_CONFIG_ID" },
|
||||
{ EGL_SAMPLES, "EGL_SAMPLES" },
|
||||
};
|
||||
|
||||
for (int i = 0; i < (int)(sizeof(vals)/sizeof(vals[0])); i++) {
|
||||
EGLint value;
|
||||
eglGetConfigAttrib(egl_dpy, config, vals[i].value, &value);
|
||||
INFO_LOG(G3D, " %s = %d", vals[i].name, value);
|
||||
}
|
||||
}
|
||||
|
||||
const char *cInterfaceEGL::EGLGetErrorString(EGLint error) {
|
||||
switch (error) {
|
||||
case EGL_SUCCESS: return "EGL_SUCCESS";
|
||||
case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
|
||||
case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
|
||||
case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
|
||||
case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
|
||||
case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
|
||||
case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
|
||||
case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
|
||||
case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
|
||||
case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
|
||||
case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
|
||||
case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
|
||||
case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
|
||||
case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
|
||||
case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
|
||||
default:
|
||||
return "(UNKNOWN)";
|
||||
}
|
||||
}
|
||||
|
||||
// Create rendering window.
|
||||
bool cInterfaceEGL::Create(void *window_handle, bool core, bool use16bit)
|
||||
{
|
||||
const char *s;
|
||||
EGLint egl_major, egl_minor;
|
||||
|
||||
egl_dpy = OpenDisplay();
|
||||
|
||||
if (!egl_dpy)
|
||||
{
|
||||
INFO_LOG(G3D, "Error: eglGetDisplay() failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!eglInitialize(egl_dpy, &egl_major, &egl_minor))
|
||||
{
|
||||
INFO_LOG(G3D, "Error: eglInitialize() failed\n");
|
||||
return false;
|
||||
}
|
||||
INFO_LOG(G3D, "eglInitialize() succeeded\n");
|
||||
|
||||
if (s_opengl_mode == MODE_DETECT || s_opengl_mode == MODE_DETECT_ES)
|
||||
DetectMode();
|
||||
|
||||
int attribs32[] = {
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, // Keep this first!
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_ALPHA_SIZE, 8,
|
||||
EGL_DEPTH_SIZE, 16,
|
||||
EGL_STENCIL_SIZE, 8,
|
||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||
EGL_TRANSPARENT_TYPE, EGL_NONE,
|
||||
EGL_SAMPLES, 0,
|
||||
EGL_NONE, 0
|
||||
};
|
||||
int attribs16[] = {
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, // Keep this first!
|
||||
EGL_RED_SIZE, 5,
|
||||
EGL_GREEN_SIZE, 6,
|
||||
EGL_BLUE_SIZE, 5,
|
||||
EGL_ALPHA_SIZE, 0,
|
||||
EGL_DEPTH_SIZE, 16,
|
||||
EGL_STENCIL_SIZE, 8,
|
||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||
EGL_TRANSPARENT_TYPE, EGL_NONE,
|
||||
EGL_SAMPLES, 0,
|
||||
EGL_NONE, 0
|
||||
};
|
||||
int *attribs = attribs32;
|
||||
if (use16bit) {
|
||||
attribs = attribs16;
|
||||
}
|
||||
|
||||
EGLint ctx_attribs[] = {
|
||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
EGL_NONE, 0
|
||||
};
|
||||
|
||||
switch (s_opengl_mode) {
|
||||
case MODE_OPENGL:
|
||||
attribs[1] = EGL_OPENGL_BIT;
|
||||
ctx_attribs[0] = EGL_NONE;
|
||||
break;
|
||||
case MODE_OPENGLES2:
|
||||
attribs[1] = EGL_OPENGL_ES2_BIT;
|
||||
ctx_attribs[1] = 2;
|
||||
break;
|
||||
case MODE_OPENGLES3:
|
||||
attribs[1] = (1 << 6); /* EGL_OPENGL_ES3_BIT_KHR */
|
||||
ctx_attribs[1] = 3;
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(G3D, "Unknown OpenGL mode set\n");
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
EGLConfig *configs;
|
||||
EGLint num_configs;
|
||||
if (!eglChooseConfig(egl_dpy, attribs, NULL, 0, &num_configs) || num_configs == 0) {
|
||||
INFO_LOG(G3D, "Error: couldn't get a number of configs\n");
|
||||
eglTerminate(egl_dpy);
|
||||
return false;
|
||||
}
|
||||
|
||||
configs = new EGLConfig[num_configs];
|
||||
|
||||
if (!eglChooseConfig(egl_dpy, attribs, configs, num_configs, &num_configs)) {
|
||||
INFO_LOG(G3D, "Error: couldn't get an EGL visual config\n");
|
||||
eglTerminate(egl_dpy);
|
||||
return false;
|
||||
}
|
||||
|
||||
INFO_LOG(G3D, "eglChooseConfig successful: num_configs=%d, choosing config 0", num_configs);
|
||||
for (int i = 0; i < num_configs; i++) {
|
||||
INFO_LOG(G3D, "Config %d:", i);
|
||||
LogEGLConfig(egl_dpy, configs[i]);
|
||||
}
|
||||
|
||||
if (s_opengl_mode == MODE_OPENGL)
|
||||
eglBindAPI(EGL_OPENGL_API);
|
||||
else
|
||||
eglBindAPI(EGL_OPENGL_ES_API);
|
||||
|
||||
EGLNativeWindowType host_window = (EGLNativeWindowType) window_handle;
|
||||
EGLNativeWindowType native_window = InitializePlatform(host_window, configs[0]);
|
||||
|
||||
s = eglQueryString(egl_dpy, EGL_VERSION);
|
||||
INFO_LOG(G3D, "EGL_VERSION = %s\n", s);
|
||||
|
||||
s = eglQueryString(egl_dpy, EGL_VENDOR);
|
||||
INFO_LOG(G3D, "EGL_VENDOR = %s\n", s);
|
||||
|
||||
s = eglQueryString(egl_dpy, EGL_EXTENSIONS);
|
||||
INFO_LOG(G3D, "EGL_EXTENSIONS = %s\n", s);
|
||||
|
||||
s = eglQueryString(egl_dpy, EGL_CLIENT_APIS);
|
||||
INFO_LOG(G3D, "EGL_CLIENT_APIS = %s\n", s);
|
||||
|
||||
egl_ctx = eglCreateContext(egl_dpy, configs[0], EGL_NO_CONTEXT, ctx_attribs);
|
||||
if (!egl_ctx) {
|
||||
INFO_LOG(G3D, "Error: eglCreateContext failed: %s\n", EGLGetErrorString(eglGetError()));
|
||||
eglTerminate(egl_dpy);
|
||||
delete[] configs;
|
||||
return false;
|
||||
}
|
||||
|
||||
egl_surf = eglCreateWindowSurface(egl_dpy, configs[0], native_window, nullptr);
|
||||
if (!egl_surf) {
|
||||
INFO_LOG(G3D, "Error: eglCreateWindowSurface failed: native_window=%p error=%s ctx_attribs[1]==%d\n", native_window, EGLGetErrorString(eglGetError()), ctx_attribs[1]);
|
||||
|
||||
eglDestroyContext(egl_dpy, egl_ctx);
|
||||
eglTerminate(egl_dpy);
|
||||
delete[] configs;
|
||||
return false;
|
||||
}
|
||||
|
||||
delete[] configs;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cInterfaceEGL::MakeCurrent()
|
||||
{
|
||||
return eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx);
|
||||
}
|
||||
|
||||
bool cInterfaceEGL::ClearCurrent()
|
||||
{
|
||||
return eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
}
|
||||
|
||||
void cInterfaceEGL::Shutdown()
|
||||
{
|
||||
ShutdownPlatform();
|
||||
if (egl_ctx && !eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx))
|
||||
NOTICE_LOG(G3D, "Could not release drawing context.");
|
||||
if (egl_ctx)
|
||||
{
|
||||
eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
if (!eglDestroyContext(egl_dpy, egl_ctx))
|
||||
NOTICE_LOG(G3D, "Could not destroy drawing context.");
|
||||
if (!eglDestroySurface(egl_dpy, egl_surf))
|
||||
NOTICE_LOG(G3D, "Could not destroy window surface.");
|
||||
if (!eglTerminate(egl_dpy))
|
||||
NOTICE_LOG(G3D, "Could not destroy display connection.");
|
||||
egl_ctx = nullptr;
|
||||
egl_dpy = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <EGL/egl.h>
|
||||
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
|
||||
class cInterfaceEGL : public cInterfaceBase
|
||||
{
|
||||
protected:
|
||||
void DetectMode();
|
||||
EGLSurface egl_surf;
|
||||
EGLContext egl_ctx;
|
||||
EGLDisplay egl_dpy;
|
||||
|
||||
virtual EGLDisplay OpenDisplay() = 0;
|
||||
virtual EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) = 0;
|
||||
virtual void ShutdownPlatform() = 0;
|
||||
virtual void SetInternalResolution(int internalWidth, int internalHeight) {}
|
||||
const char *EGLGetErrorString(EGLint error);
|
||||
|
||||
public:
|
||||
void SwapInterval(int Interval);
|
||||
void Swap();
|
||||
void SetMode(u32 mode) { s_opengl_mode = mode; }
|
||||
void* GetFuncAddress(const std::string& name);
|
||||
bool Create(void *window_handle, bool core, bool use16bit) override;
|
||||
bool MakeCurrent();
|
||||
bool ClearCurrent();
|
||||
void Shutdown();
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/Log.h"
|
||||
#include "Common/GL/GLInterface/EGLAndroid.h"
|
||||
|
||||
EGLDisplay cInterfaceEGLAndroid::OpenDisplay() {
|
||||
return eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
}
|
||||
|
||||
EGLNativeWindowType cInterfaceEGLAndroid::InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) {
|
||||
EGLint format;
|
||||
if (EGL_FALSE == eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &format)) {
|
||||
ERROR_LOG(G3D, "Failed getting EGL_NATIVE_VISUAL_ID: error %s", EGLGetErrorString(eglGetError()));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ANativeWindow_setBuffersGeometry(host_window, internalWidth_, internalHeight_, format);
|
||||
|
||||
const int width = ANativeWindow_getWidth(host_window);
|
||||
const int height = ANativeWindow_getHeight(host_window);
|
||||
SetBackBufferDimensions(width, height);
|
||||
|
||||
return host_window;
|
||||
}
|
||||
|
||||
void cInterfaceEGLAndroid::ShutdownPlatform() {
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/GL/GLInterface/EGL.h"
|
||||
|
||||
class cInterfaceEGLAndroid : public cInterfaceEGL {
|
||||
public:
|
||||
cInterfaceEGLAndroid() : internalWidth_(0), internalHeight_(0) {}
|
||||
protected:
|
||||
EGLDisplay OpenDisplay() override;
|
||||
EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) override;
|
||||
void ShutdownPlatform() override;
|
||||
void OverrideBackbufferDimensions(int internalWidth, int internalHeight) override {
|
||||
internalWidth_ = internalWidth;
|
||||
internalHeight_ = internalHeight;
|
||||
}
|
||||
|
||||
private:
|
||||
int internalWidth_;
|
||||
int internalHeight_;
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
#include "Common/GL/GLInterface/EGLAndroid.h"
|
||||
#elif defined(__APPLE__)
|
||||
#include "Common/GL/GLInterface/AGL.h"
|
||||
#elif defined(_WIN32)
|
||||
#include "Common/GL/GLInterface/WGL.h"
|
||||
#elif HAVE_X11
|
||||
#if defined(USE_EGL) && USE_EGL
|
||||
#include "Common/GL/GLInterface/EGLX11.h"
|
||||
#else
|
||||
#include "Common/GL/GLInterface/GLX.h"
|
||||
#endif
|
||||
#else
|
||||
#error Platform doesnt have a GLInterface
|
||||
#endif
|
||||
|
||||
cInterfaceBase* HostGL_CreateGLInterface(){
|
||||
#ifdef ANDROID
|
||||
return new cInterfaceEGLAndroid;
|
||||
#elif defined(__APPLE__)
|
||||
return new cInterfaceAGL;
|
||||
#elif defined(_WIN32)
|
||||
return new cInterfaceWGL;
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
#if defined(USE_EGL) && USE_EGL
|
||||
return new cInterfaceEGLX11;
|
||||
#else
|
||||
return new cInterfaceGLX;
|
||||
#endif
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
enum GLInterfaceMode {
|
||||
MODE_DETECT = 0,
|
||||
MODE_DETECT_ES,
|
||||
MODE_OPENGL,
|
||||
MODE_OPENGLES2,
|
||||
MODE_OPENGLES3,
|
||||
};
|
||||
|
||||
class cInterfaceBase {
|
||||
protected:
|
||||
// Window dimensions.
|
||||
u32 s_backbuffer_width;
|
||||
u32 s_backbuffer_height;
|
||||
|
||||
u32 s_opengl_mode;
|
||||
public:
|
||||
cInterfaceBase() : s_backbuffer_width(0), s_backbuffer_height(0), s_opengl_mode(MODE_DETECT) {}
|
||||
virtual ~cInterfaceBase() {}
|
||||
virtual void Swap() {}
|
||||
virtual void SetMode(u32 mode) { s_opengl_mode = GLInterfaceMode::MODE_OPENGL; }
|
||||
virtual u32 GetMode() { return s_opengl_mode; }
|
||||
virtual void* GetFuncAddress(const std::string& name) { return nullptr; }
|
||||
virtual bool Create(void *window_handle, bool core = true, bool use16bit = false) = 0;
|
||||
virtual bool MakeCurrent() { return true; }
|
||||
virtual bool ClearCurrent() { return true; }
|
||||
virtual void Shutdown() {}
|
||||
|
||||
virtual void SwapInterval(int Interval) { }
|
||||
virtual u32 GetBackBufferWidth() { return s_backbuffer_width; }
|
||||
virtual u32 GetBackBufferHeight() { return s_backbuffer_height; }
|
||||
|
||||
virtual void OverrideBackbufferDimensions(int w, int h) = 0;
|
||||
|
||||
virtual void SetBackBufferDimensions(u32 W, u32 H) {s_backbuffer_width = W; s_backbuffer_height = H; }
|
||||
virtual void Update() { }
|
||||
virtual bool PeekMessages() { return false; }
|
||||
};
|
||||
|
||||
|
||||
cInterfaceBase* HostGL_CreateGLInterface();
|
||||
@@ -637,6 +637,7 @@ UI::EventReturn GameSettingsScreen::OnHardwareTransform(UI::EventParams &e) {
|
||||
}
|
||||
|
||||
UI::EventReturn GameSettingsScreen::OnScreenRotation(UI::EventParams &e) {
|
||||
ILOG("New display rotation: %d", g_Config.iScreenRotation);
|
||||
System_SendMessage("rotate", "");
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
+3
-2
@@ -210,7 +210,8 @@ void QtHost::ShutdownSound() { }
|
||||
std::string NativeQueryConfig(std::string query) {
|
||||
char temp[128];
|
||||
if (query == "screenRotation") {
|
||||
sprintf(temp, "%i", g_Config.iScreenRotation);
|
||||
ILOG("g_Config.screenRotation = %d", g_Config.iScreenRotation);
|
||||
snprintf(temp, sizeof(temp), "%d", g_Config.iScreenRotation);
|
||||
return std::string(temp);
|
||||
} else if (query == "immersiveMode") {
|
||||
return std::string(g_Config.bImmersiveMode ? "1" : "0");
|
||||
@@ -224,7 +225,7 @@ std::string NativeQueryConfig(std::string query) {
|
||||
}
|
||||
|
||||
int max_res = std::max(System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES)) / 480 + 1;
|
||||
sprintf(temp, "%i", std::min(scale, max_res));
|
||||
snprintf(temp, sizeof(temp), "%d", std::min(scale, max_res));
|
||||
return std::string(temp);
|
||||
} else if (query == "force44khz") {
|
||||
return std::string("0");
|
||||
|
||||
@@ -99,8 +99,14 @@ ARCH_FILES := \
|
||||
ArmEmitterTest.cpp
|
||||
endif
|
||||
|
||||
EGL_FILES := \
|
||||
$(SRC)/Common/GL/GLInterface/EGL.cpp \
|
||||
$(SRC)/Common/GL/GLInterface/EGLAndroid.cpp \
|
||||
$(SRC)/Common/GL/GLInterface/GLInterface.cpp
|
||||
|
||||
EXEC_AND_LIB_FILES := \
|
||||
$(ARCH_FILES) \
|
||||
$(EGL_FILES) \
|
||||
TestRunner.cpp \
|
||||
$(SRC)/Core/MIPS/MIPS.cpp.arm \
|
||||
$(SRC)/Core/MIPS/MIPSAnalyst.cpp \
|
||||
|
||||
@@ -15,7 +15,7 @@ LOCAL_C_INCLUDES := \
|
||||
$(LOCAL_PATH)
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := native libzip
|
||||
LOCAL_LDLIBS := -lz -lGLESv2 -lOpenSLES -lEGL -ldl -llog
|
||||
LOCAL_LDLIBS := -lz -landroid -lGLESv2 -lOpenSLES -lEGL -ldl -llog
|
||||
|
||||
# ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
ifeq ($(findstring armeabi-v7a,$(TARGET_ARCH_ABI)),armeabi-v7a)
|
||||
|
||||
+231
-105
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <jni.h>
|
||||
#include <android/log.h>
|
||||
#include <android/native_window_jni.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <GLES2/gl2.h>
|
||||
@@ -27,6 +28,8 @@
|
||||
#include "android/jni/native_audio.h"
|
||||
#include "gfx/gl_common.h"
|
||||
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
|
||||
#include "app-android.h"
|
||||
|
||||
static JNIEnv *jniEnvUI;
|
||||
@@ -61,11 +64,29 @@ static int androidVersion;
|
||||
static int deviceType;
|
||||
|
||||
// Should only be used for display detection during startup (for config defaults etc)
|
||||
// This is the ACTUAL display size, not the hardware scaled display size.
|
||||
static int display_dpi;
|
||||
static int display_xres;
|
||||
static int display_yres;
|
||||
static int backbuffer_format; // Android PixelFormat enum
|
||||
|
||||
static int desiredBackbufferSizeX;
|
||||
static int desiredBackbufferSizeY;
|
||||
|
||||
static jmethodID postCommand;
|
||||
static jobject nativeActivity;
|
||||
static volatile bool exitRenderLoop;
|
||||
bool renderLoopRunning;
|
||||
|
||||
float dp_xscale = 1.0f;
|
||||
float dp_yscale = 1.0f;
|
||||
|
||||
InputState input_state;
|
||||
|
||||
static bool renderer_inited = false;
|
||||
static bool first_lost = true;
|
||||
static std::string library_path;
|
||||
|
||||
|
||||
// Android implementation of callbacks to the Java part of the app
|
||||
void SystemToast(const char *text) {
|
||||
@@ -143,18 +164,6 @@ int System_GetPropertyInt(SystemProperty prop) {
|
||||
}
|
||||
}
|
||||
|
||||
// Remember that all of these need initialization on init! The process
|
||||
// may be reused when restarting the game. Globals are DANGEROUS.
|
||||
|
||||
float dp_xscale = 1.0f;
|
||||
float dp_yscale = 1.0f;
|
||||
|
||||
InputState input_state;
|
||||
|
||||
static bool renderer_inited = false;
|
||||
static bool first_lost = true;
|
||||
static std::string library_path;
|
||||
|
||||
std::string GetJavaString(JNIEnv *env, jstring jstr) {
|
||||
const char *str = env->GetStringUTFChars(jstr, 0);
|
||||
std::string cpp_string = std::string(str);
|
||||
@@ -202,7 +211,7 @@ extern "C" jstring Java_org_ppsspp_ppsspp_NativeApp_queryConfig
|
||||
}
|
||||
|
||||
extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
|
||||
(JNIEnv *env, jclass, jstring jmodel, jint jdeviceType, jint jxres, jint jyres, jstring jlangRegion, jstring japkpath,
|
||||
(JNIEnv *env, jclass, jstring jmodel, jint jdeviceType, jstring jlangRegion, jstring japkpath,
|
||||
jstring jdataDir, jstring jexternalDir, jstring jlibraryDir, jstring jshortcutParam,
|
||||
jstring jinstallID, jint jAndroidVersion) {
|
||||
jniEnvUI = env;
|
||||
@@ -226,8 +235,6 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
|
||||
right_joystick_y_async = 0;
|
||||
hat_joystick_x_async = 0;
|
||||
hat_joystick_y_async = 0;
|
||||
display_xres = jxres;
|
||||
display_yres = jyres;
|
||||
|
||||
std::string apkPath = GetJavaString(env, japkpath);
|
||||
VFSRegister("", new ZipAssetReader(apkPath.c_str(), "assets/"));
|
||||
@@ -313,97 +320,8 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) {
|
||||
ILOG("NativeApp.shutdown() -- end");
|
||||
}
|
||||
|
||||
extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, jobject obj) {
|
||||
ILOG("NativeApp.displayInit()");
|
||||
if (!renderer_inited) {
|
||||
NativeInitGraphics();
|
||||
renderer_inited = true;
|
||||
} else {
|
||||
NativeDeviceLost(); // ???
|
||||
ILOG("displayInit: NativeDeviceLost completed.");
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayResize(JNIEnv *, jobject clazz, jint w, jint h, jint dpi, jfloat refreshRate) {
|
||||
ILOG("NativeApp.displayResize(%i x %i, dpi=%i, refresh=%0.2f)", w, h, dpi, refreshRate);
|
||||
|
||||
g_dpi = dpi;
|
||||
g_dpi_scale = 240.0f / (float)g_dpi;
|
||||
|
||||
pixel_xres = w;
|
||||
pixel_yres = h;
|
||||
dp_xres = pixel_xres * g_dpi_scale;
|
||||
dp_yres = pixel_yres * g_dpi_scale;
|
||||
dp_xscale = (float)dp_xres / pixel_xres;
|
||||
dp_yscale = (float)dp_yres / pixel_yres;
|
||||
display_hz = refreshRate;
|
||||
|
||||
NativeResized();
|
||||
}
|
||||
|
||||
extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayRender(JNIEnv *env, jobject obj) {
|
||||
static bool hasSetThreadName = false;
|
||||
if (!hasSetThreadName) {
|
||||
hasSetThreadName = true;
|
||||
setCurrentThreadName("AndroidRender");
|
||||
}
|
||||
|
||||
if (renderer_inited) {
|
||||
// TODO: Look into if these locks are a perf loss
|
||||
{
|
||||
lock_guard guard(input_state.lock);
|
||||
|
||||
input_state.pad_lstick_x = left_joystick_x_async;
|
||||
input_state.pad_lstick_y = left_joystick_y_async;
|
||||
input_state.pad_rstick_x = right_joystick_x_async;
|
||||
input_state.pad_rstick_y = right_joystick_y_async;
|
||||
|
||||
UpdateInputState(&input_state);
|
||||
}
|
||||
NativeUpdate(input_state);
|
||||
|
||||
{
|
||||
lock_guard guard(input_state.lock);
|
||||
EndInputState(&input_state);
|
||||
}
|
||||
|
||||
NativeRender();
|
||||
time_update();
|
||||
} else {
|
||||
ELOG("BAD: Ended up in nativeRender even though app has quit.%s", "");
|
||||
// Shouldn't really get here. Let's draw magenta.
|
||||
glDepthMask(GL_TRUE);
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glClearColor(1.0, 0.0, 1.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
}
|
||||
|
||||
lock_guard guard(frameCommandLock);
|
||||
if (!nativeActivity) {
|
||||
while (!frameCommands.empty())
|
||||
frameCommands.pop();
|
||||
return;
|
||||
}
|
||||
while (!frameCommands.empty()) {
|
||||
FrameCommand frameCmd;
|
||||
frameCmd = frameCommands.front();
|
||||
frameCommands.pop();
|
||||
|
||||
DLOG("frameCommand %s %s", frameCmd.command.c_str(), frameCmd.params.c_str());
|
||||
|
||||
jstring cmd = env->NewStringUTF(frameCmd.command.c_str());
|
||||
jstring param = env->NewStringUTF(frameCmd.params.c_str());
|
||||
env->CallVoidMethod(nativeActivity, postCommand, cmd, param);
|
||||
env->DeleteLocalRef(cmd);
|
||||
env->DeleteLocalRef(param);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayShutdown(JNIEnv *env, jobject obj) {
|
||||
if (renderer_inited) {
|
||||
NativeDeviceLost();
|
||||
ILOG("NativeDeviceLost completed.");
|
||||
NativeShutdownGraphics();
|
||||
renderer_inited = false;
|
||||
NativeMessageReceived("recreateviews", "");
|
||||
}
|
||||
@@ -538,7 +456,7 @@ extern "C" jboolean JNICALL Java_org_ppsspp_ppsspp_NativeApp_accelerometer(JNIEn
|
||||
return retvalX || retvalY || retvalZ;
|
||||
}
|
||||
|
||||
extern "C" void Java_org_ppsspp_ppsspp_NativeApp_sendMessage(JNIEnv *env, jclass, jstring message, jstring param) {
|
||||
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendMessage(JNIEnv *env, jclass, jstring message, jstring param) {
|
||||
std::string msg = GetJavaString(env, message);
|
||||
std::string prm = GetJavaString(env, param);
|
||||
|
||||
@@ -547,3 +465,211 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_sendMessage(JNIEnv *env, jclass
|
||||
}
|
||||
NativeMessageReceived(msg.c_str(), prm.c_str());
|
||||
}
|
||||
|
||||
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeActivity_exitEGLRenderLoop(JNIEnv *env, jobject obj) {
|
||||
if (!renderLoopRunning) {
|
||||
ELOG("Render loop already exited");
|
||||
return;
|
||||
}
|
||||
exitRenderLoop = true;
|
||||
while (renderLoopRunning) {
|
||||
sleep_ms(10);
|
||||
}
|
||||
}
|
||||
|
||||
void correctRatio(int &sz_x, int &sz_y, float scale) {
|
||||
float x = (float)sz_x;
|
||||
float y = (float)sz_y;
|
||||
float ratio = x / y;
|
||||
ILOG("CorrectRatio: Considering size: %0.2f/%0.2f=%0.2f for scale %f", x, y, ratio, scale);
|
||||
float targetRatio;
|
||||
|
||||
// Try to get the longest dimension to match scale*PSP resolution.
|
||||
if (x >= y) {
|
||||
targetRatio = 480.0f / 272.0f;
|
||||
x = 480.f * scale;
|
||||
y = 272.f * scale;
|
||||
} else {
|
||||
targetRatio = 272.0f / 480.0f;
|
||||
x = 272.0f * scale;
|
||||
y = 480.0f * scale;
|
||||
}
|
||||
|
||||
float correction = targetRatio / ratio;
|
||||
ILOG("Target ratio: %0.2f ratio: %0.2f correction: %0.2f", targetRatio, ratio, correction);
|
||||
if (ratio < targetRatio) {
|
||||
y *= correction;
|
||||
} else {
|
||||
x /= correction;
|
||||
}
|
||||
|
||||
sz_x = x;
|
||||
sz_y = y;
|
||||
ILOG("Corrected ratio: %dx%d", sz_x, sz_y);
|
||||
}
|
||||
|
||||
void getDesiredBackbufferSize(int &sz_x, int &sz_y) {
|
||||
sz_x = display_xres;
|
||||
sz_y = display_yres;
|
||||
std::string config = NativeQueryConfig("hwScale");
|
||||
int scale;
|
||||
if (1 == sscanf(config.c_str(), "%d", &scale) && scale > 0) {
|
||||
correctRatio(sz_x, sz_y, scale);
|
||||
} else {
|
||||
sz_x = 0;
|
||||
sz_y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_setDisplayParameters(JNIEnv *, jclass, jint xres, jint yres, jint dpi, jfloat refreshRate) {
|
||||
ILOG("NativeApp.setDisplayParameters(%d x %d, dpi=%d, refresh=%0.2f)", xres, yres, dpi, refreshRate);
|
||||
display_xres = xres;
|
||||
display_yres = yres;
|
||||
display_dpi = dpi;
|
||||
display_hz = refreshRate;
|
||||
}
|
||||
|
||||
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv *, jclass, jint bufw, jint bufh, jint format) {
|
||||
ILOG("NativeApp.backbufferResize(%d x %d)", bufw, bufh);
|
||||
|
||||
// pixel_*res is the backbuffer resolution.
|
||||
pixel_xres = bufw;
|
||||
pixel_yres = bufh;
|
||||
backbuffer_format = format;
|
||||
|
||||
g_dpi = (int)display_dpi;
|
||||
g_dpi_scale = 240.0f / (float)g_dpi;
|
||||
|
||||
dp_xres = display_xres * g_dpi_scale;
|
||||
dp_yres = display_yres * g_dpi_scale;
|
||||
|
||||
// Touch scaling is from display pixels to dp pixels.
|
||||
dp_xscale = (float)dp_xres / (float)display_xres;
|
||||
dp_yscale = (float)dp_yres / (float)display_yres;
|
||||
|
||||
pixel_in_dps = (float)pixel_xres / dp_xres;
|
||||
|
||||
ILOG("dp_xscale=%f dp_yscale=%f", dp_xscale, dp_yscale);
|
||||
ILOG("dp_xres=%d dp_yres=%d", dp_xres, dp_yres);
|
||||
ILOG("pixel_xres=%d pixel_yres=%d", pixel_xres, pixel_yres);
|
||||
ILOG("g_dpi=%d g_dpi_scale=%f", g_dpi, g_dpi_scale);
|
||||
|
||||
NativeResized();
|
||||
}
|
||||
|
||||
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_computeDesiredBackbufferDimensions() {
|
||||
getDesiredBackbufferSize(desiredBackbufferSizeX, desiredBackbufferSizeY);
|
||||
}
|
||||
|
||||
extern "C" jint JNICALL Java_org_ppsspp_ppsspp_NativeApp_getDesiredBackbufferWidth(JNIEnv *, jclass) {
|
||||
return desiredBackbufferSizeX;
|
||||
}
|
||||
|
||||
extern "C" jint JNICALL Java_org_ppsspp_ppsspp_NativeApp_getDesiredBackbufferHeight(JNIEnv *, jclass) {
|
||||
return desiredBackbufferSizeY;
|
||||
}
|
||||
|
||||
extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(JNIEnv *env, jobject obj, jobject _surf) {
|
||||
ANativeWindow *wnd = ANativeWindow_fromSurface(env, _surf);
|
||||
|
||||
WLOG("runEGLRenderLoop. display_xres=%d display_yres=%d", display_xres, display_yres);
|
||||
|
||||
if (wnd == nullptr) {
|
||||
ELOG("Error: Surface is null.");
|
||||
return false;
|
||||
}
|
||||
|
||||
cInterfaceBase *gl = HostGL_CreateGLInterface();
|
||||
if (!gl) {
|
||||
ELOG("ERROR: Failed to create GL interface");
|
||||
return false;
|
||||
}
|
||||
ILOG("EGL interface created. Desired backbuffer size: %dx%d", desiredBackbufferSizeX, desiredBackbufferSizeY);
|
||||
|
||||
// Apparently we still have to set this through Java through setFixedSize on the bufferHolder for it to take effect...
|
||||
gl->SetBackBufferDimensions(desiredBackbufferSizeX, desiredBackbufferSizeY);
|
||||
gl->SetMode(MODE_DETECT_ES);
|
||||
|
||||
bool use565 = false;
|
||||
switch (backbuffer_format) {
|
||||
case 4: // PixelFormat.RGB_565
|
||||
use565 = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!gl->Create(wnd, false, use565)) {
|
||||
ELOG("EGL creation failed");
|
||||
// TODO: What do we do now?
|
||||
return false;
|
||||
}
|
||||
gl->MakeCurrent();
|
||||
|
||||
if (!renderer_inited) {
|
||||
NativeInitGraphics();
|
||||
renderer_inited = true;
|
||||
}
|
||||
|
||||
exitRenderLoop = false;
|
||||
renderLoopRunning = true;
|
||||
|
||||
while (!exitRenderLoop) {
|
||||
static bool hasSetThreadName = false;
|
||||
if (!hasSetThreadName) {
|
||||
hasSetThreadName = true;
|
||||
setCurrentThreadName("AndroidRender");
|
||||
}
|
||||
|
||||
// TODO: Look into if these locks are a perf loss
|
||||
{
|
||||
lock_guard guard(input_state.lock);
|
||||
|
||||
input_state.pad_lstick_x = left_joystick_x_async;
|
||||
input_state.pad_lstick_y = left_joystick_y_async;
|
||||
input_state.pad_rstick_x = right_joystick_x_async;
|
||||
input_state.pad_rstick_y = right_joystick_y_async;
|
||||
|
||||
UpdateInputState(&input_state);
|
||||
}
|
||||
NativeUpdate(input_state);
|
||||
|
||||
{
|
||||
lock_guard guard(input_state.lock);
|
||||
EndInputState(&input_state);
|
||||
}
|
||||
|
||||
NativeRender();
|
||||
time_update();
|
||||
|
||||
gl->Swap();
|
||||
|
||||
lock_guard guard(frameCommandLock);
|
||||
while (!frameCommands.empty()) {
|
||||
FrameCommand frameCmd;
|
||||
frameCmd = frameCommands.front();
|
||||
frameCommands.pop();
|
||||
|
||||
WLOG("frameCommand! '%s' '%s'", frameCmd.command.c_str(), frameCmd.params.c_str());
|
||||
|
||||
jstring cmd = env->NewStringUTF(frameCmd.command.c_str());
|
||||
jstring param = env->NewStringUTF(frameCmd.params.c_str());
|
||||
env->CallVoidMethod(nativeActivity, postCommand, cmd, param);
|
||||
env->DeleteLocalRef(cmd);
|
||||
env->DeleteLocalRef(param);
|
||||
}
|
||||
}
|
||||
|
||||
// Restore lost device objects. TODO: This feels like the wrong place for this.
|
||||
NativeDeviceLost();
|
||||
ILOG("NativeDeviceLost completed.");
|
||||
|
||||
NativeShutdownGraphics();
|
||||
renderer_inited = false;
|
||||
|
||||
gl->ClearCurrent();
|
||||
delete gl;
|
||||
|
||||
ANativeWindow_release(wnd);
|
||||
renderLoopRunning = false;
|
||||
WLOG("Render loop exited;");
|
||||
return true;
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import java.util.Locale;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.UiModeManager;
|
||||
import android.content.Context;
|
||||
@@ -16,11 +15,9 @@ import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ConfigurationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Point;
|
||||
import android.media.AudioManager;
|
||||
import android.net.Uri;
|
||||
@@ -29,6 +26,7 @@ import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Vibrator;
|
||||
import android.text.InputType;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.Gravity;
|
||||
@@ -37,6 +35,8 @@ import android.view.InputEvent;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.View;
|
||||
import android.view.View.OnSystemUiVisibilityChangeListener;
|
||||
import android.view.Window;
|
||||
@@ -46,57 +46,54 @@ import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class NativeActivity extends Activity {
|
||||
public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
// Remember to loadLibrary your JNI .so in a static {} block
|
||||
|
||||
// Adjust these as necessary
|
||||
private static String TAG = "NativeActivity";
|
||||
|
||||
|
||||
// Allows us to skip a lot of initialization on secondary calls to onCreate.
|
||||
private static boolean initialized = false;
|
||||
|
||||
|
||||
// Graphics and audio interfaces
|
||||
private NativeGLView mGLSurfaceView;
|
||||
protected NativeRenderer nativeRenderer;
|
||||
|
||||
private NativeSurfaceView mSurfaceView;
|
||||
private Surface mSurface;
|
||||
private Thread mRenderLoopThread;
|
||||
|
||||
private String shortcutParam = "";
|
||||
|
||||
|
||||
public static String runCommand;
|
||||
public static String commandParameter;
|
||||
public static String installID;
|
||||
|
||||
|
||||
// Remember settings for best audio latency
|
||||
private int optimalFramesPerBuffer;
|
||||
private int optimalSampleRate;
|
||||
|
||||
|
||||
// audioFocusChangeListener to listen to changes in audio state
|
||||
private AudioFocusChangeListener audioFocusChangeListener;
|
||||
private AudioManager audioManager;
|
||||
|
||||
|
||||
private Vibrator vibrator;
|
||||
|
||||
private boolean isXperiaPlay;
|
||||
|
||||
|
||||
// Allow for multiple connected gamepads but just consider them the same for now.
|
||||
// Actually this is not entirely true, see the code.
|
||||
InputDeviceState inputPlayerA;
|
||||
InputDeviceState inputPlayerB;
|
||||
InputDeviceState inputPlayerC;
|
||||
String inputPlayerADesc;
|
||||
|
||||
|
||||
// Functions for the app activity to override to change behaviour.
|
||||
|
||||
|
||||
public native void registerCallbacks();
|
||||
public native void unregisterCallbacks();
|
||||
|
||||
public boolean useLowProfileButtons() {
|
||||
return true;
|
||||
}
|
||||
|
||||
NativeRenderer getRenderer() {
|
||||
return nativeRenderer;
|
||||
}
|
||||
|
||||
|
||||
@TargetApi(17)
|
||||
private void detectOptimalAudioSettings() {
|
||||
try {
|
||||
@@ -110,8 +107,8 @@ public class NativeActivity extends Activity {
|
||||
// Ignore, if we can't parse it it's bogus and zero is a fine value (means we couldn't detect it).
|
||||
}
|
||||
}
|
||||
|
||||
String getApplicationLibraryDir(ApplicationInfo application) {
|
||||
|
||||
String getApplicationLibraryDir(ApplicationInfo application) {
|
||||
String libdir = null;
|
||||
try {
|
||||
// Starting from Android 2.3, nativeLibraryDir is available:
|
||||
@@ -159,33 +156,29 @@ public class NativeActivity extends Activity {
|
||||
size.y = d.getHeight();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setShortcutParam(String shortcutParam) {
|
||||
this.shortcutParam = ((shortcutParam == null) ? "" : shortcutParam);
|
||||
}
|
||||
|
||||
|
||||
public void Initialize() {
|
||||
// Initialize audio classes. Do this here since detectOptimalAudioSettings()
|
||||
// needs audioManager
|
||||
this.audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
|
||||
this.audioFocusChangeListener = new AudioFocusChangeListener();
|
||||
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 17) {
|
||||
// Get the optimal buffer sz
|
||||
detectOptimalAudioSettings();
|
||||
}
|
||||
|
||||
// isLandscape is used to trigger GetAppInfo currently, we
|
||||
boolean landscape = NativeApp.isLandscape();
|
||||
Log.d(TAG, "Landscape: " + landscape);
|
||||
|
||||
// Get system information
|
||||
ApplicationInfo appInfo = null;
|
||||
ApplicationInfo appInfo = null;
|
||||
PackageManager packMgmr = getPackageManager();
|
||||
String packageName = getPackageName();
|
||||
try {
|
||||
appInfo = packMgmr.getApplicationInfo(packageName, 0);
|
||||
} catch (NameNotFoundException e) {
|
||||
} catch (NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("Unable to locate assets, aborting...");
|
||||
}
|
||||
@@ -205,42 +198,22 @@ public class NativeActivity extends Activity {
|
||||
}
|
||||
|
||||
isXperiaPlay = IsXperiaPlay();
|
||||
|
||||
|
||||
String libraryDir = getApplicationLibraryDir(appInfo);
|
||||
File sdcard = Environment.getExternalStorageDirectory();
|
||||
|
||||
String externalStorageDir = sdcard.getAbsolutePath();
|
||||
String externalStorageDir = sdcard.getAbsolutePath();
|
||||
String dataDir = this.getFilesDir().getAbsolutePath();
|
||||
String apkFilePath = appInfo.sourceDir;
|
||||
String apkFilePath = appInfo.sourceDir;
|
||||
|
||||
String model = Build.MANUFACTURER + ":" + Build.MODEL;
|
||||
String languageRegion = Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry();
|
||||
String languageRegion = Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry();
|
||||
|
||||
Point displaySize = new Point();
|
||||
GetScreenSize(displaySize);
|
||||
NativeApp.audioConfig(optimalFramesPerBuffer, optimalSampleRate);
|
||||
NativeApp.init(model, deviceType, displaySize.x, displaySize.y, languageRegion, apkFilePath, dataDir, externalStorageDir, libraryDir, shortcutParam, installID, Build.VERSION.SDK_INT);
|
||||
NativeApp.init(model, deviceType, languageRegion, apkFilePath, dataDir, externalStorageDir, libraryDir, shortcutParam, installID, Build.VERSION.SDK_INT);
|
||||
|
||||
NativeApp.sendMessage("cacheDir", getCacheDir().getAbsolutePath());
|
||||
|
||||
// OK, config should be initialized, we can query for screen rotation.
|
||||
if (Build.VERSION.SDK_INT >= 9) {
|
||||
updateScreenRotation();
|
||||
}
|
||||
|
||||
// Detect OpenGL support.
|
||||
// We don't currently use this detection for anything but good to have in the log.
|
||||
if (!detectOpenGLES20()) {
|
||||
Log.i(TAG, "OpenGL ES 2.0 NOT detected. Things will likely go badly.");
|
||||
} else {
|
||||
if (detectOpenGLES30()) {
|
||||
Log.i(TAG, "OpenGL ES 3.0 detected.");
|
||||
}
|
||||
else {
|
||||
Log.i(TAG, "OpenGL ES 2.0 detected.");
|
||||
}
|
||||
}
|
||||
|
||||
vibrator = (Vibrator)getSystemService(VIBRATOR_SERVICE);
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
checkForVibrator();
|
||||
@@ -258,6 +231,8 @@ public class NativeActivity extends Activity {
|
||||
Log.e(TAG, "Invalid rotation: " + rotString);
|
||||
return;
|
||||
}
|
||||
Log.i(TAG, "Setting requested rotation: " + rot + " ('" + rotString + "')");
|
||||
|
||||
switch (rot) {
|
||||
case 0:
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
||||
@@ -276,10 +251,12 @@ public class NativeActivity extends Activity {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean useImmersive() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
|
||||
return false;
|
||||
String immersive = NativeApp.queryConfig("immersiveMode");
|
||||
return immersive.equals("1") && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
|
||||
return immersive.equals("1");
|
||||
}
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
@@ -298,7 +275,7 @@ public class NativeActivity extends Activity {
|
||||
Log.e(TAG, "updateSystemUiVisibility: decor view not yet created, ignoring");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Need API 11 to check for existence of a vibrator? Zany.
|
||||
@TargetApi(11)
|
||||
public void checkForVibrator() {
|
||||
@@ -309,71 +286,67 @@ public class NativeActivity extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
// Override this to scale the backbuffer (use the Android hardware scaler)
|
||||
public void getDesiredBackbufferSize(Point sz) {
|
||||
sz.x = 0;
|
||||
sz.y = 0;
|
||||
private Runnable mEmulationRunner = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Bit of a hack - loop until onSurfaceCreated succeeds.
|
||||
try {
|
||||
while (mSurface == null)
|
||||
Thread.sleep(10);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Log.i(TAG, "Starting the render loop: " + mSurface);
|
||||
// Start emulation using the provided Surface.
|
||||
if (!runEGLRenderLoop(mSurface)) {
|
||||
// TODO: Add an alert dialog or something
|
||||
Log.e(TAG, "Failed to start up OpenGL");
|
||||
}
|
||||
Log.i(TAG, "Left the render loop: " + mSurface);
|
||||
}
|
||||
};
|
||||
|
||||
public native boolean runEGLRenderLoop(Surface surface);
|
||||
// Tells the render loop thread to exit, so we can restart it.
|
||||
public native void exitEGLRenderLoop();
|
||||
|
||||
void updateDisplayMetrics(Point outSize) {
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
Display display = getWindowManager().getDefaultDisplay();
|
||||
display.getMetrics(metrics);
|
||||
|
||||
float refreshRate = display.getRefreshRate();
|
||||
if (outSize == null) {
|
||||
outSize = new Point();
|
||||
}
|
||||
GetScreenSize(outSize);
|
||||
NativeApp.setDisplayParameters(outSize.x, outSize.y, metrics.densityDpi, refreshRate);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
super.onCreate(savedInstanceState);
|
||||
registerCallbacks();
|
||||
installID = Installation.id(this);
|
||||
|
||||
updateDisplayMetrics(null);
|
||||
|
||||
if (!initialized) {
|
||||
Initialize();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
// OK, config should be initialized, we can query for screen rotation.
|
||||
updateScreenRotation();
|
||||
|
||||
// Keep the screen bright - very annoying if it goes dark when tilting away
|
||||
Window window = this.getWindow();
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
||||
|
||||
|
||||
gainAudioFocus(this.audioManager, this.audioFocusChangeListener);
|
||||
NativeApp.audioInit();
|
||||
|
||||
mGLSurfaceView = new NativeGLView(this);
|
||||
nativeRenderer = new NativeRenderer(this);
|
||||
|
||||
Point sz = new Point();
|
||||
getDesiredBackbufferSize(sz);
|
||||
if (sz.x > 0) {
|
||||
Log.i(TAG, "Requesting fixed size buffer: " + sz.x + "x" + sz.y);
|
||||
// Auto-calculates new DPI and forwards to the correct call on mGLSurfaceView.getHolder()
|
||||
nativeRenderer.setFixedSize(sz.x, sz.y, mGLSurfaceView);
|
||||
}
|
||||
mGLSurfaceView.setEGLContextClientVersion(2);
|
||||
|
||||
// Setup the GLSurface and ask android for the correct
|
||||
// Number of bits for r, g, b, a, depth and stencil components
|
||||
// The PSP only has 16-bit Z so that should be enough.
|
||||
// Might want to change this for other apps (24-bit might be useful).
|
||||
// Actually, we might be able to do without both stencil and depth in
|
||||
// the back buffer, but that would kill non-buffered rendering.
|
||||
|
||||
// It appears some gingerbread devices blow up if you use a config chooser at all ???? (Xperia Play)
|
||||
//if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
|
||||
// On some (especially older devices), things blow up later (EGL_BAD_MATCH) if we don't set the format here,
|
||||
// if we specify that we want destination alpha in the config chooser, which we do.
|
||||
// http://grokbase.com/t/gg/android-developers/11bj40jm4w/fall-back
|
||||
|
||||
|
||||
// Needed to avoid banding on Ouya?
|
||||
if (Build.MANUFACTURER == "OUYA") {
|
||||
mGLSurfaceView.getHolder().setFormat(PixelFormat.RGBX_8888);
|
||||
mGLSurfaceView.setEGLConfigChooser(new NativeEGLConfigChooser());
|
||||
} else {
|
||||
// Many devices require that we set a config chooser, despite the documentation
|
||||
// explicitly stating: "If no setEGLConfigChooser method is called, then by default the view will choose an RGB_888 surface with a depth buffer depth of at least 16 bits."
|
||||
// On these devices, I get these crashes: http://stackoverflow.com/questions/14167319/android-opengl-demo-no-config-chosen
|
||||
// So let's try it...
|
||||
mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 8);
|
||||
}
|
||||
|
||||
mGLSurfaceView.setRenderer(nativeRenderer);
|
||||
setContentView(mGLSurfaceView);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
updateSystemUiVisibility();
|
||||
@@ -381,8 +354,62 @@ public class NativeActivity extends Activity {
|
||||
setupSystemUiCallback();
|
||||
}
|
||||
}
|
||||
updateDisplayMetrics(null);
|
||||
|
||||
NativeApp.computeDesiredBackbufferDimensions();
|
||||
int bbW = NativeApp.getDesiredBackbufferWidth();
|
||||
int bbH = NativeApp.getDesiredBackbufferHeight();
|
||||
|
||||
mSurfaceView = new NativeSurfaceView(NativeActivity.this, bbW, bbH);
|
||||
mSurfaceView.getHolder().addCallback(NativeActivity.this);
|
||||
Log.i(TAG, "setcontentview before");
|
||||
setContentView(mSurfaceView);
|
||||
Log.i(TAG, "setcontentview after");
|
||||
|
||||
mRenderLoopThread = new Thread(mEmulationRunner);
|
||||
mRenderLoopThread.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder)
|
||||
{
|
||||
Log.d(TAG, "Surface created.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
|
||||
{
|
||||
Log.w(TAG, "Surface changed. Resolution: " + width + "x" + height + " Format: " + format);
|
||||
// Make sure we have fresh display metrics so the computations go right.
|
||||
// This is needed on some very old devices, I guess event order is different or something...
|
||||
Point sz = new Point();
|
||||
updateDisplayMetrics(sz);
|
||||
NativeApp.backbufferResize(width, height, format);
|
||||
mSurface = holder.getSurface();
|
||||
if (mRenderLoopThread == null || !mRenderLoopThread.isAlive()) {
|
||||
mRenderLoopThread = new Thread(mEmulationRunner);
|
||||
mRenderLoopThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder)
|
||||
{
|
||||
mSurface = null;
|
||||
Log.w(TAG, "Surface destroyed.");
|
||||
if (mRenderLoopThread != null && mRenderLoopThread.isAlive()) {
|
||||
// This will wait until the thread has exited.
|
||||
exitEGLRenderLoop();
|
||||
try {
|
||||
mRenderLoopThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@TargetApi(19)
|
||||
void setupSystemUiCallback() {
|
||||
getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() {
|
||||
@@ -394,48 +421,36 @@ public class NativeActivity extends Activity {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
exitEGLRenderLoop();
|
||||
super.onStop();
|
||||
Log.i(TAG, "onStop - do nothing special");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
Log.i(TAG, "onDestroy");
|
||||
mGLSurfaceView.onDestroy();
|
||||
nativeRenderer.onDestroyed();
|
||||
mSurfaceView.onDestroy();
|
||||
NativeApp.audioShutdown();
|
||||
// Probably vain attempt to help the garbage collector...
|
||||
mGLSurfaceView = null;
|
||||
mSurfaceView = null;
|
||||
audioFocusChangeListener = null;
|
||||
audioManager = null;
|
||||
unregisterCallbacks();
|
||||
}
|
||||
|
||||
private boolean detectOpenGLES20() {
|
||||
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
|
||||
ConfigurationInfo info = am.getDeviceConfigurationInfo();
|
||||
return info.reqGlEsVersion >= 0x20000;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean detectOpenGLES30() {
|
||||
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
|
||||
ConfigurationInfo info = am.getDeviceConfigurationInfo();
|
||||
return info.reqGlEsVersion >= 0x30000;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
Log.i(TAG, "onPause");
|
||||
loseAudioFocus(this.audioManager, this.audioFocusChangeListener);
|
||||
NativeApp.pause();
|
||||
mGLSurfaceView.onPause();
|
||||
mSurfaceView.onPause();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
@@ -443,33 +458,27 @@ public class NativeActivity extends Activity {
|
||||
updateSystemUiVisibility();
|
||||
}
|
||||
// OK, config should be initialized, we can query for screen rotation.
|
||||
if (Build.VERSION.SDK_INT >= 9) {
|
||||
updateScreenRotation();
|
||||
}
|
||||
updateScreenRotation();
|
||||
|
||||
Log.i(TAG, "onResume");
|
||||
if (mGLSurfaceView != null) {
|
||||
mGLSurfaceView.onResume();
|
||||
if (mSurfaceView != null) {
|
||||
mSurfaceView.onResume();
|
||||
} else {
|
||||
Log.e(TAG, "mGLSurfaceView really shouldn't be null in onResume");
|
||||
}
|
||||
|
||||
|
||||
gainAudioFocus(this.audioManager, this.audioFocusChangeListener);
|
||||
NativeApp.resume();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
Log.i(TAG, "onConfigurationChanged");
|
||||
super.onConfigurationChanged(newConfig);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
updateSystemUiVisibility();
|
||||
}
|
||||
|
||||
Point sz = new Point();
|
||||
getDesiredBackbufferSize(sz);
|
||||
if (sz.x > 0) {
|
||||
mGLSurfaceView.getHolder().setFixedSize(sz.x/2, sz.y/2);
|
||||
}
|
||||
updateDisplayMetrics(null);
|
||||
}
|
||||
|
||||
//keep this static so we can call this even if we don't
|
||||
@@ -480,7 +489,7 @@ public class NativeActivity extends Activity {
|
||||
AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//keep this static so we can call this even if we don't
|
||||
//instantiate NativeAudioPlayer
|
||||
public static void loseAudioFocus(AudioManager audioManager,AudioFocusChangeListener focusChangeListener){
|
||||
@@ -488,7 +497,7 @@ public class NativeActivity extends Activity {
|
||||
audioManager.abandonAudioFocus(focusChangeListener);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// We simply grab the first input device to produce an event and ignore all others that are connected.
|
||||
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
|
||||
private InputDeviceState getInputDeviceState(InputEvent event) {
|
||||
@@ -579,11 +588,11 @@ public class NativeActivity extends Activity {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Let's go through the old path (onKeyUp, onKeyDown).
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TargetApi(16)
|
||||
static public String getInputDesc(InputDevice input) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
@@ -648,7 +657,7 @@ public class NativeActivity extends Activity {
|
||||
case KeyEvent.KEYCODE_SEARCH:
|
||||
NativeApp.keyDown(0, keyCode, repeat);
|
||||
return true;
|
||||
|
||||
|
||||
case KeyEvent.KEYCODE_DPAD_UP:
|
||||
case KeyEvent.KEYCODE_DPAD_DOWN:
|
||||
case KeyEvent.KEYCODE_DPAD_LEFT:
|
||||
@@ -703,12 +712,12 @@ public class NativeActivity extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@TargetApi(11)
|
||||
private AlertDialog.Builder createDialogBuilderWithTheme() {
|
||||
return new AlertDialog.Builder(this, AlertDialog.THEME_HOLO_DARK);
|
||||
}
|
||||
|
||||
|
||||
// The return value is sent elsewhere. TODO in java, in SendMessage in C++.
|
||||
public void inputBox(String title, String defaultText, String defaultAction) {
|
||||
final FrameLayout fl = new FrameLayout(this);
|
||||
@@ -722,7 +731,7 @@ public class NativeActivity extends Activity {
|
||||
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||
input.setText(defaultText);
|
||||
input.selectAll();
|
||||
|
||||
|
||||
AlertDialog.Builder bld = null;
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
|
||||
bld = new AlertDialog.Builder(this);
|
||||
@@ -733,22 +742,24 @@ public class NativeActivity extends Activity {
|
||||
.setView(fl)
|
||||
.setTitle(title)
|
||||
.setPositiveButton(defaultAction, new DialogInterface.OnClickListener(){
|
||||
public void onClick(DialogInterface d, int which) {
|
||||
@Override
|
||||
public void onClick(DialogInterface d, int which) {
|
||||
NativeApp.sendMessage("inputbox_completed", input.getText().toString());
|
||||
d.dismiss();
|
||||
}
|
||||
})
|
||||
.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
|
||||
public void onClick(DialogInterface d, int which) {
|
||||
@Override
|
||||
public void onClick(DialogInterface d, int which) {
|
||||
NativeApp.sendMessage("inputbox_failed", "");
|
||||
d.cancel();
|
||||
}
|
||||
}).create();
|
||||
|
||||
|
||||
dlg.setCancelable(true);
|
||||
dlg.show();
|
||||
}
|
||||
|
||||
|
||||
public boolean processCommand(String command, String params) {
|
||||
if (command.equals("launchBrowser")) {
|
||||
try {
|
||||
@@ -825,18 +836,18 @@ public class NativeActivity extends Activity {
|
||||
toast.show();
|
||||
Log.i(TAG, params);
|
||||
return true;
|
||||
} else if (command.equals("showKeyboard") && mGLSurfaceView != null) {
|
||||
} else if (command.equals("showKeyboard") && mSurfaceView != null) {
|
||||
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
// No idea what the point of the ApplicationWindowToken is or if it
|
||||
// matters where we get it from...
|
||||
inputMethodManager.toggleSoftInputFromWindow(
|
||||
mGLSurfaceView.getApplicationWindowToken(),
|
||||
mSurfaceView.getApplicationWindowToken(),
|
||||
InputMethodManager.SHOW_FORCED, 0);
|
||||
return true;
|
||||
} else if (command.equals("hideKeyboard") && mGLSurfaceView != null) {
|
||||
} else if (command.equals("hideKeyboard") && mSurfaceView != null) {
|
||||
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
inputMethodManager.toggleSoftInputFromWindow(
|
||||
mGLSurfaceView.getApplicationWindowToken(),
|
||||
mSurfaceView.getApplicationWindowToken(),
|
||||
InputMethodManager.SHOW_FORCED, 0);
|
||||
return true;
|
||||
} else if (command.equals("inputbox")) {
|
||||
@@ -850,7 +861,7 @@ public class NativeActivity extends Activity {
|
||||
Log.i(TAG, "Launching inputbox: " + title + " " + defString);
|
||||
inputBox(title, defString, "OK");
|
||||
return true;
|
||||
} else if (command.equals("vibrate") && mGLSurfaceView != null) {
|
||||
} else if (command.equals("vibrate") && mSurfaceView != null) {
|
||||
int milliseconds = -1;
|
||||
if (params != "") {
|
||||
try {
|
||||
@@ -867,13 +878,13 @@ public class NativeActivity extends Activity {
|
||||
// permission.
|
||||
switch (milliseconds) {
|
||||
case -1:
|
||||
mGLSurfaceView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
mSurfaceView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
break;
|
||||
case -2:
|
||||
mGLSurfaceView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
|
||||
mSurfaceView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
|
||||
break;
|
||||
case -3:
|
||||
mGLSurfaceView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
mSurfaceView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
break;
|
||||
default:
|
||||
if (vibrator != null) {
|
||||
@@ -885,14 +896,16 @@ public class NativeActivity extends Activity {
|
||||
} else if (command.equals("finish")) {
|
||||
finish();
|
||||
} else if (command.equals("rotate")) {
|
||||
if (Build.VERSION.SDK_INT >= 9) {
|
||||
updateScreenRotation();
|
||||
}
|
||||
updateScreenRotation();
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
Log.i(TAG, "Must recreate activity on rotation");
|
||||
}
|
||||
} else if (command.equals("immersive")) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
updateSystemUiVisibility();
|
||||
}
|
||||
} else if (command.equals("recreate")) {
|
||||
exitEGLRenderLoop();
|
||||
recreate();
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -1,24 +1,31 @@
|
||||
package org.ppsspp.ppsspp;
|
||||
|
||||
|
||||
// Note that the display* methods are in NativeRenderer.java
|
||||
// Note that the display* methods are in NativeRenderer.java
|
||||
|
||||
public class NativeApp {
|
||||
public final static int DEVICE_ID_DEFAULT = 0;
|
||||
public final static int DEVICE_ID_KEYBOARD = 1;
|
||||
public final static int DEVICE_ID_MOUSE = 2;
|
||||
public final static int DEVICE_ID_PAD_0 = 10;
|
||||
|
||||
public final static int DEVICE_ID_DEFAULT = 0;
|
||||
public final static int DEVICE_ID_KEYBOARD = 1;
|
||||
public final static int DEVICE_ID_MOUSE = 2;
|
||||
public final static int DEVICE_ID_PAD_0 = 10;
|
||||
|
||||
public final static int DEVICE_TYPE_MOBILE = 0;
|
||||
public final static int DEVICE_TYPE_TV = 1;
|
||||
public final static int DEVICE_TYPE_DESKTOP = 2;
|
||||
|
||||
public static native void init(String model, int deviceType, int xres, int yres, String languageRegion, String apkPath, String dataDir, String externalDir, String libraryDir, String shortcutParam, String installID, int androidVersion);
|
||||
|
||||
public static native void init(String model, int deviceType, String languageRegion, String apkPath, String dataDir, String externalDir, String libraryDir, String shortcutParam, String installID, int androidVersion);
|
||||
|
||||
public static native void audioInit();
|
||||
public static native void audioShutdown();
|
||||
public static native void audioConfig(int optimalFramesPerBuffer, int optimalSampleRate);
|
||||
|
||||
|
||||
public static native void computeDesiredBackbufferDimensions();
|
||||
public static native int getDesiredBackbufferWidth();
|
||||
public static native int getDesiredBackbufferHeight();
|
||||
|
||||
public static native void setDisplayParameters(int display_xres, int display_yres, int dpi, float refreshRate);
|
||||
public static native void backbufferResize(int bufferWidth, int bufferHeight, int format);
|
||||
|
||||
public static native boolean isLandscape();
|
||||
public static native boolean isAtTopLevel();
|
||||
|
||||
@@ -35,7 +42,7 @@ public class NativeApp {
|
||||
public static native void beginJoystickEvent();
|
||||
public static native void joystickAxis(int deviceId, int axis, float value);
|
||||
public static native void endJoystickEvent();
|
||||
|
||||
|
||||
public static native boolean mouseWheelEvent(float x, float y);
|
||||
|
||||
// will only be called between init() and shutdown()
|
||||
@@ -47,7 +54,6 @@ public class NativeApp {
|
||||
public static native boolean accelerometer(float x, float y, float z);
|
||||
|
||||
public static native void sendMessage(String msg, String arg);
|
||||
|
||||
|
||||
public static native String queryConfig(String queryName);
|
||||
}
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
package org.ppsspp.ppsspp;
|
||||
|
||||
import javax.microedition.khronos.egl.EGL10;
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.egl.EGLDisplay;
|
||||
|
||||
import android.opengl.GLSurfaceView.EGLConfigChooser;
|
||||
import android.util.Log;
|
||||
|
||||
public class NativeEGLConfigChooser implements EGLConfigChooser {
|
||||
private static final String TAG = "NativeEGLConfigChooser";
|
||||
|
||||
private static final int EGL_OPENGL_ES2_BIT = 4;
|
||||
|
||||
private class ConfigAttribs {
|
||||
EGLConfig config;
|
||||
public int red;
|
||||
public int green;
|
||||
public int blue;
|
||||
public int alpha;
|
||||
public int stencil;
|
||||
public int depth;
|
||||
public int samples;
|
||||
public void Log() {
|
||||
Log.i(TAG, "EGLConfig: red=" + red + " green=" + green + " blue=" + blue + " alpha=" + alpha + " depth=" + depth + " stencil=" + stencil + " samples=" + samples);
|
||||
}
|
||||
}
|
||||
|
||||
int getEglConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config, int attr) {
|
||||
int[] value = new int[1];
|
||||
try {
|
||||
if (egl.eglGetConfigAttrib(display, config, attr, value))
|
||||
return value[0];
|
||||
else
|
||||
return -1;
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (config == null) {
|
||||
Log.e(TAG, "Called getEglConfigAttrib with null config. Bad developer.");
|
||||
} else {
|
||||
Log.e(TAG, "Illegal argument to getEglConfigAttrib: attr=" + attr);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ConfigAttribs[] getConfigAttribs(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {
|
||||
ConfigAttribs[] attr = new ConfigAttribs[configs.length];
|
||||
for (int i = 0; i < configs.length; i++) {
|
||||
ConfigAttribs cfg = new ConfigAttribs();
|
||||
cfg.config = configs[i];
|
||||
cfg.red = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_RED_SIZE);
|
||||
cfg.green = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_GREEN_SIZE);
|
||||
cfg.blue = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_BLUE_SIZE);
|
||||
cfg.alpha = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_ALPHA_SIZE);
|
||||
cfg.depth = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_DEPTH_SIZE);
|
||||
cfg.stencil = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_STENCIL_SIZE);
|
||||
cfg.samples = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_SAMPLES);
|
||||
attr[i] = cfg;
|
||||
}
|
||||
return attr;
|
||||
}
|
||||
|
||||
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
|
||||
// The absolute minimum. We will do our best to choose a better config though.
|
||||
int[] configSpec = {
|
||||
EGL10.EGL_RED_SIZE, 5,
|
||||
EGL10.EGL_GREEN_SIZE, 6,
|
||||
EGL10.EGL_BLUE_SIZE, 5,
|
||||
EGL10.EGL_DEPTH_SIZE, 16,
|
||||
EGL10.EGL_STENCIL_SIZE, 0,
|
||||
EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
|
||||
EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL10.EGL_NONE
|
||||
};
|
||||
|
||||
int[] num_config = new int[1];
|
||||
if (!egl.eglChooseConfig(display, configSpec, null, 0, num_config)) {
|
||||
throw new IllegalArgumentException("eglChooseConfig failed when counting");
|
||||
}
|
||||
|
||||
int numConfigs = num_config[0];
|
||||
Log.i(TAG, "There are " + numConfigs + " egl configs");
|
||||
if (numConfigs <= 0) {
|
||||
throw new IllegalArgumentException("No configs match configSpec");
|
||||
}
|
||||
|
||||
EGLConfig[] eglConfigs = new EGLConfig[numConfigs];
|
||||
if (!egl.eglChooseConfig(display, configSpec, eglConfigs, numConfigs, num_config)) {
|
||||
throw new IllegalArgumentException("eglChooseConfig failed when retrieving");
|
||||
}
|
||||
|
||||
ConfigAttribs [] configs = getConfigAttribs(egl, display, eglConfigs);
|
||||
|
||||
ConfigAttribs chosen = null;
|
||||
|
||||
// Log them all.
|
||||
for (int i = 0; i < configs.length; i++) {
|
||||
configs[i].Log();
|
||||
}
|
||||
|
||||
// We now ignore destination alpha as a workaround for the Mali issue
|
||||
// where we get badly composited if we use it.
|
||||
|
||||
// First, find our ideal configuration. Prefer depth.
|
||||
for (int i = 0; i < configs.length; i++) {
|
||||
ConfigAttribs c = configs[i];
|
||||
if (c.red == 8 && c.green == 8 && c.blue == 8 && c.alpha == 0 && c.stencil >= 8 && c.depth >= 24) {
|
||||
chosen = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (chosen == null) {
|
||||
// Then, prefer one with 20-bit depth (Tegra 3)
|
||||
for (int i = 0; i < configs.length; i++) {
|
||||
ConfigAttribs c = configs[i];
|
||||
if (c.red == 8 && c.green == 8 && c.blue == 8 && c.alpha == 0 && c.stencil >= 8 && c.depth >= 20) {
|
||||
chosen = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chosen == null) {
|
||||
// Second, accept one with 16-bit depth.
|
||||
for (int i = 0; i < configs.length; i++) {
|
||||
ConfigAttribs c = configs[i];
|
||||
if (c.red == 8 && c.green == 8 && c.blue == 8 && c.alpha == 0 && c.stencil >= 8 && c.depth >= 16) {
|
||||
chosen = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chosen == null) {
|
||||
// Third, accept one with no stencil.
|
||||
for (int i = 0; i < configs.length; i++) {
|
||||
ConfigAttribs c = configs[i];
|
||||
if (c.red == 8 && c.green == 8 && c.blue == 8 && c.alpha == 0 && c.depth >= 16) {
|
||||
chosen = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chosen == null) {
|
||||
// Third, accept one with alpha but with stencil, 24-bit depth.
|
||||
for (int i = 0; i < configs.length; i++) {
|
||||
ConfigAttribs c = configs[i];
|
||||
if (c.red == 8 && c.green == 8 && c.blue == 8 && c.alpha == 8 && c.stencil >= 8 && c.depth >= 24) {
|
||||
chosen = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chosen == null) {
|
||||
// Third, accept one with alpha but with stencil, 16-bit depth.
|
||||
for (int i = 0; i < configs.length; i++) {
|
||||
ConfigAttribs c = configs[i];
|
||||
if (c.red == 8 && c.green == 8 && c.blue == 8 && c.alpha == 8 && c.stencil >= 8 && c.depth >= 16) {
|
||||
chosen = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chosen == null) {
|
||||
// Fourth, accept one with 16-bit color but depth and stencil required.
|
||||
for (int i = 0; i < configs.length; i++) {
|
||||
ConfigAttribs c = configs[i];
|
||||
if (c.red >= 5 && c.green >= 6 && c.blue >= 5 && c.depth >= 16 && c.stencil >= 8) {
|
||||
chosen = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chosen == null) {
|
||||
// Fifth, accept one with 16-bit color but depth required.
|
||||
for (int i = 0; i < configs.length; i++) {
|
||||
ConfigAttribs c = configs[i];
|
||||
if (c.red >= 5 && c.green >= 6 && c.blue >= 5 && c.depth >= 16) {
|
||||
chosen = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chosen == null) {
|
||||
// Final, accept the first one in the list.
|
||||
if (configs.length > 0)
|
||||
chosen = configs[0];
|
||||
}
|
||||
|
||||
if (chosen == null) {
|
||||
throw new IllegalArgumentException("Failed to find a valid EGL config");
|
||||
}
|
||||
|
||||
Log.i(TAG, "Final chosen config: ");
|
||||
chosen.Log();
|
||||
return chosen.config;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
package org.ppsspp.ppsspp;
|
||||
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.opengl.GLES20;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
|
||||
public class NativeRenderer implements GLSurfaceView.Renderer {
|
||||
private static String TAG = "NativeRenderer";
|
||||
private NativeActivity mActivity;
|
||||
private boolean isDark = false;
|
||||
private int dpi;
|
||||
private float refreshRate;
|
||||
|
||||
private double dpi_scale_x;
|
||||
private double dpi_scale_y;
|
||||
|
||||
int last_width, last_height;
|
||||
|
||||
NativeRenderer(NativeActivity act) {
|
||||
mActivity = act;
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
Display display = act.getWindowManager().getDefaultDisplay();
|
||||
display.getMetrics(metrics);
|
||||
dpi = metrics.densityDpi;
|
||||
|
||||
refreshRate = display.getRefreshRate();
|
||||
}
|
||||
|
||||
double getDpiScaleX() {
|
||||
return dpi_scale_x;
|
||||
}
|
||||
double getDpiScaleY() {
|
||||
return dpi_scale_y;
|
||||
}
|
||||
|
||||
public void setDark(boolean d) {
|
||||
isDark = d;
|
||||
}
|
||||
|
||||
public void setFixedSize(int xres, int yres, GLSurfaceView surfaceView) {
|
||||
Log.i(TAG, "Setting surface to fixed size " + xres + "x" + yres);
|
||||
surfaceView.getHolder().setFixedSize(xres, yres);
|
||||
}
|
||||
|
||||
public void onDrawFrame(GL10 unused /*use GLES20*/) {
|
||||
if (isDark) {
|
||||
GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
|
||||
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_STENCIL_BUFFER_BIT);
|
||||
} else {
|
||||
displayRender();
|
||||
}
|
||||
}
|
||||
|
||||
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
|
||||
// Log.i(TAG, "onSurfaceCreated - EGL context is new or was lost");
|
||||
// Actually, it seems that it is here we should recreate lost GL objects.
|
||||
displayInit();
|
||||
}
|
||||
|
||||
public void onSurfaceChanged(GL10 unused, int width, int height) {
|
||||
Point sz = new Point();
|
||||
mActivity.GetScreenSize(sz);
|
||||
double actualW = sz.x;
|
||||
double actualH = sz.y;
|
||||
dpi_scale_x = ((double)width / (double)actualW);
|
||||
dpi_scale_y = ((double)height / (double)actualH);
|
||||
Log.i(TAG, "onSurfaceChanged: " + dpi_scale_x + "x" + dpi_scale_y + " (width=" + width + ", actualW=" + actualW);
|
||||
int scaled_dpi = (int)((double)dpi * dpi_scale_x);
|
||||
displayResize(width, height, scaled_dpi, refreshRate);
|
||||
last_width = width;
|
||||
last_height = height;
|
||||
}
|
||||
|
||||
// Not override, it's custom.
|
||||
public void onDestroyed() {
|
||||
displayShutdown();
|
||||
}
|
||||
|
||||
// NATIVE METHODS
|
||||
|
||||
// Note: This also means "device lost" and you should reload
|
||||
// all buffered objects.
|
||||
public native void displayInit();
|
||||
public native void displayResize(int w, int h, int dpi, float refreshRate);
|
||||
public native void displayRender();
|
||||
public native void displayShutdown();
|
||||
}
|
||||
+43
-50
@@ -1,59 +1,54 @@
|
||||
package org.ppsspp.ppsspp;
|
||||
|
||||
// Touch- and sensor-enabled GLSurfaceView.
|
||||
// Touch- and sensor-enabled SurfaceView.
|
||||
// Supports simple multitouch and pressure.
|
||||
// DPI scaling is handled by the native code.
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
// import android.os.Build;
|
||||
// import android.util.Log;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.SurfaceView;
|
||||
|
||||
import com.bda.controller.*;
|
||||
|
||||
public class NativeGLView extends GLSurfaceView implements SensorEventListener, ControllerListener {
|
||||
private static String TAG = "NativeGLView";
|
||||
public class NativeSurfaceView extends SurfaceView implements SensorEventListener, ControllerListener {
|
||||
private static String TAG = "NativeSurfaceView";
|
||||
private SensorManager mSensorManager;
|
||||
private Sensor mAccelerometer;
|
||||
private NativeActivity mActivity;
|
||||
|
||||
|
||||
// Moga controller
|
||||
private Controller mController = null;
|
||||
private boolean isMogaPro = false;
|
||||
|
||||
public NativeGLView(NativeActivity activity) {
|
||||
super(activity);
|
||||
mActivity = activity;
|
||||
|
||||
/*// TODO: This would be nice.
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
try {
|
||||
Method method_setPreserveEGLContextOnPause = GLSurfaceView.class.getMethod(
|
||||
"setPreserveEGLContextOnPause", new Class[] { Boolean.class });
|
||||
Log.i(TAG, "Invoking setPreserveEGLContextOnPause");
|
||||
method_setPreserveEGLContextOnPause.invoke(this, true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}*/
|
||||
|
||||
public NativeSurfaceView(NativeActivity activity, int fixedW, int fixedH) {
|
||||
super(activity);
|
||||
|
||||
Log.i(TAG, "NativeSurfaceView");
|
||||
|
||||
mSensorManager = (SensorManager)activity.getSystemService(Activity.SENSOR_SERVICE);
|
||||
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
|
||||
|
||||
mController = Controller.getInstance(activity);
|
||||
|
||||
// Maybe we need to use this?
|
||||
if (fixedW != 0 && fixedH != 0) {
|
||||
Log.i(TAG, "Setting surface holder to use a fixed size of " + fixedW + "x" + fixedH + " pixels");
|
||||
this.getHolder().setFixedSize(fixedW, fixedH);
|
||||
} else {
|
||||
Log.i(TAG, "Using default backbuffer size.");
|
||||
}
|
||||
|
||||
// this.getHolder().setFormat(PixelFormat.RGBA_8888);
|
||||
|
||||
try {
|
||||
MogaHack.init(mController, activity);
|
||||
Log.i(TAG, "MOGA initialized");
|
||||
@@ -67,19 +62,19 @@ public class NativeGLView extends GLSurfaceView implements SensorEventListener,
|
||||
private int getToolType(final MotionEvent ev, int pointer) {
|
||||
return ev.getToolType(pointer);
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
public boolean onTouchEvent(final MotionEvent ev) {
|
||||
boolean canReadToolType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
|
||||
|
||||
int numTouchesHandled = 0;
|
||||
float scaleX = (float)mActivity.getRenderer().getDpiScaleX();
|
||||
float scaleY = (float)mActivity.getRenderer().getDpiScaleY();
|
||||
for (int i = 0; i < ev.getPointerCount(); i++) {
|
||||
int pid = ev.getPointerId(i);
|
||||
int code = 0;
|
||||
|
||||
|
||||
final int action = ev.getActionMasked();
|
||||
|
||||
|
||||
// These code bits are now the same as the constants in input_state.h.
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
@@ -98,23 +93,25 @@ public class NativeGLView extends GLSurfaceView implements SensorEventListener,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (code != 0) {
|
||||
if (canReadToolType) {
|
||||
int tool = getToolType(ev, i);
|
||||
code |= tool << 10; // We use the Android tool type codes
|
||||
}
|
||||
// Can't use || due to short circuit evaluation
|
||||
numTouchesHandled += NativeApp.touch(scaleX * ev.getX(i), scaleY * ev.getY(i), code, pid) ? 1 : 0;
|
||||
numTouchesHandled += NativeApp.touch(ev.getX(i), ev.getY(i), code, pid) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
return numTouchesHandled > 0;
|
||||
}
|
||||
|
||||
// Sensor management
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int arg1) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER) {
|
||||
return;
|
||||
@@ -122,41 +119,37 @@ public class NativeGLView extends GLSurfaceView implements SensorEventListener,
|
||||
// Can also look at event.timestamp for accuracy magic
|
||||
NativeApp.accelerometer(event.values[0], event.values[1], event.values[2]);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
mSensorManager.unregisterListener(this);
|
||||
if (mController != null) {
|
||||
mController.onPause();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
|
||||
if (mController != null) {
|
||||
mController.onResume();
|
||||
|
||||
|
||||
// According to the docs, the Moga's state can be inconsistent here.
|
||||
// We should do a one time poll. TODO
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void onDestroy() {
|
||||
if (mController != null) {
|
||||
mController.exit();
|
||||
mController.exit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MOGA Controller - from ControllerListener
|
||||
@Override
|
||||
public void onKeyEvent(KeyEvent event) {
|
||||
// The Moga left stick doubles as a D-pad. This creates mapping conflicts so let's turn it off.
|
||||
// Unfortunately this breaks menu navigation in PPSSPP currently but meh.
|
||||
// This is different on Moga Pro though.
|
||||
|
||||
|
||||
if (!isMogaPro) {
|
||||
switch (event.getKeyCode()) {
|
||||
case KeyEvent.KEYCODE_DPAD_DOWN:
|
||||
@@ -216,7 +209,7 @@ public class NativeGLView extends GLSurfaceView implements SensorEventListener,
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case StateEvent.STATE_POWER_LOW:
|
||||
switch (state.getAction()) {
|
||||
case StateEvent.ACTION_TRUE:
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.ppsspp.ppsspp;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.graphics.Point;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Looper;
|
||||
@@ -11,11 +10,12 @@ public class PpssppActivity extends NativeActivity {
|
||||
private static final String TAG = "PpssppActivity";
|
||||
// Key used by shortcut.
|
||||
public static final String SHORTCUT_EXTRA_KEY = "org.ppsspp.ppsspp.Shortcuts";
|
||||
|
||||
|
||||
private static boolean m_hasUnsupportedABI = false;
|
||||
private static boolean m_hasNoNativeBinary = false;
|
||||
|
||||
static {
|
||||
@SuppressWarnings("deprecation")
|
||||
static void CheckABIAndLoadLibrary() {
|
||||
if (Build.CPU_ABI.equals("armeabi")) {
|
||||
m_hasUnsupportedABI = true;
|
||||
} else {
|
||||
@@ -28,6 +28,10 @@ public class PpssppActivity extends NativeActivity {
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
CheckABIAndLoadLibrary();
|
||||
}
|
||||
|
||||
public PpssppActivity() {
|
||||
super();
|
||||
}
|
||||
@@ -36,6 +40,7 @@ public class PpssppActivity extends NativeActivity {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
if (m_hasUnsupportedABI || m_hasNoNativeBinary) {
|
||||
new Thread() {
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void run() {
|
||||
Looper.prepare();
|
||||
@@ -47,15 +52,15 @@ public class PpssppActivity extends NativeActivity {
|
||||
}
|
||||
Looper.loop();
|
||||
}
|
||||
|
||||
|
||||
}.start();
|
||||
|
||||
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
System.exit(-1);
|
||||
return;
|
||||
}
|
||||
@@ -68,61 +73,13 @@ public class PpssppActivity extends NativeActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
|
||||
private void correctRatio(Point sz, float scale) {
|
||||
float x = sz.x;
|
||||
float y = sz.y;
|
||||
float ratio = x / y;
|
||||
// Log.i(TAG, "Considering size: " + sz.x + "x" + sz.y + "=" + ratio);
|
||||
float targetRatio;
|
||||
if (x >= y) {
|
||||
targetRatio = 480.0f / 272.0f;
|
||||
x = 480.f * scale;
|
||||
y = 272.f * scale;
|
||||
} else {
|
||||
targetRatio = 272.0f / 480.0f;
|
||||
x = 272.0f * scale;
|
||||
y = 480.0f * scale;
|
||||
}
|
||||
float correction = targetRatio / ratio;
|
||||
// Log.i(TAG, "Target ratio: " + targetRatio + " ratio: " + ratio + " correction: " + correction);
|
||||
if (ratio < targetRatio) {
|
||||
y *= correction;
|
||||
} else {
|
||||
x /= correction;
|
||||
}
|
||||
sz.x = (int)x;
|
||||
sz.y = (int)y;
|
||||
// Log.i(TAG, "Corrected ratio: " + sz.x + "x" + sz.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getDesiredBackbufferSize(Point sz) {
|
||||
GetScreenSize(sz);
|
||||
String config = NativeApp.queryConfig("hwScale");
|
||||
int scale;
|
||||
try {
|
||||
scale = Integer.parseInt(config);
|
||||
if (scale == 0) {
|
||||
sz.x = 0;
|
||||
sz.y = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
sz.x = 0;
|
||||
sz.y = 0;
|
||||
return;
|
||||
}
|
||||
correctRatio(sz, (float)scale);
|
||||
}
|
||||
|
||||
// called by the C++ code through JNI. Dispatch anything we can't directly handle
|
||||
// on the gfx thread to the UI thread.
|
||||
public void postCommand(String command, String parameter) {
|
||||
final String cmd = command;
|
||||
final String param = parameter;
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
processCommand(cmd, param);
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ Bounds UIContext::GetScissorBounds() {
|
||||
void UIContext::ActivateTopScissor() {
|
||||
if (scissorStack_.size()) {
|
||||
const Bounds &bounds = scissorStack_.back();
|
||||
float scale = 1.0f / g_dpi_scale;
|
||||
float scale = pixel_in_dps;
|
||||
int x = scale * bounds.x;
|
||||
int y = scale * bounds.y;
|
||||
int w = scale * bounds.w;
|
||||
|
||||
Reference in new issue
Block a user