Skip to content

Commit

Permalink
[Android] Show Android sample caching if Swappy is buggy
Browse files Browse the repository at this point in the history
Fix wrong logic determining if Swappy is buggy
Loosened up the thresholds a little bit
Android Sample now uses a Kotlin activity
Android Sample shows how to deal with devices that do not support Vulkan
  • Loading branch information
darksylinc committed Apr 15, 2024
1 parent 0820d68 commit cea0d20
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,10 @@ namespace Ogre
else
{
int64 currTimestamp = timeInMilliseconds();
if( currTimestamp - mFirstRecreateTimestamp <= 1000 )
if( currTimestamp - mFirstRecreateTimestamp <= 1500 )
{
++mRecreateCount;
if( mRecreateCount < 5u )
if( mRecreateCount >= 5u )
{
// We're disabling Swappy. It's likely buggy.
LogManager::getSingleton().logMessage(
Expand Down
15 changes: 13 additions & 2 deletions Samples/2.0/AndroidAppTemplate/Template/app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
apply plugin: 'com.android.application'
plugins {
id 'com.android.application'
id 'kotlin-android'
}

android {
compileSdkVersion 33
compileSdk 33
ndkVersion "25.2.9519653"

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}

defaultConfig {
applicationId "com.ogre3d.%%sampleName%%"
minSdkVersion 24
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.ogre3d.%%sampleName%%" android:versionCode="1" android:versionName="1.0">

<uses-feature
android:name="android.hardware.vulkan.version"
android:version="0x400003"
android:required="true" />

<application android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar.Fullscreen">

<!-- Our activity is the built-in NativeActivity framework class.
This will take care of integrating with our NDK code. -->
<activity android:name="android.app.NativeActivity" android:label="@string/app_name"
<activity android:name="com.ogre3d.core.DemoNativeActivity" android:label="@string/app_name"
android:exported="true"
android:configChanges="orientation|screenSize|keyboardHidden">
android:configChanges="orientation|screenSize|keyboardHidden"
android:resizeableActivity="false"
android:launchMode="singleTop">
<!-- Tell NativeActivity the name of or .so -->
<meta-data android:name="android.app.lib_name" android:value="%%sampleName%%"/>
<intent-filter>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
-----------------------------------------------------------------------------
This source file is part of OGRE-Next
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org
Copyright (c) 2000-present Torus Knot Software Ltd
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

package com.ogre3d.core

import android.app.AlertDialog
import android.app.NativeActivity
import android.graphics.Rect

class DemoNativeActivity : NativeActivity() {
fun showNoVulkanAlert(errorMsg: String, detailedErrorMsg: String) {
runOnUiThread {
var dlg = AlertDialog.Builder(this)
.setMessage("This game requires Vulkan device support. We are sorry.\nThis app cannot be run on this device. Rendering Engine said:\n\n" + errorMsg)
.setCancelable(false)
.create();
dlg.show();

// The default dialog is waaay too small. Make it bigger.
val displayRectangle = Rect()
window.getDecorView().getWindowVisibleDisplayFrame(displayRectangle);
dlg.window?.setLayout(
displayRectangle.width() * 80 / 100,
displayRectangle.height() * 80 / 100
);
}
}

fun getCacheFolder(): String {
return applicationContext.cacheDir.canonicalPath
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,36 @@ THE SOFTWARE.
#include "OgreVulkanPlugin.h"
#include "Windowing/Android/OgreVulkanAndroidWindow.h"

#include <fstream>

//-----------------------------------------------------------------------------
std::string Android_getCacheFolder()
{
android_app *app = Demo::AndroidSystems::getAndroidApp();

JNIEnv *jni = 0;
app->activity->vm->AttachCurrentThread( &jni, nullptr );

ANativeActivity *nativeActivity = app->activity;
jclass classDef = jni->GetObjectClass( nativeActivity->clazz );
jmethodID getCacheFolder = jni->GetMethodID( classDef, "getCacheFolder", "()Ljava/lang/String;" );
jstring cacheDir = (jstring)jni->CallObjectMethod( nativeActivity->clazz, getCacheFolder );

const char *cacheDirCStr = jni->GetStringUTFChars( cacheDir, nullptr );
std::string retVal( cacheDirCStr );
jni->ReleaseStringUTFChars( cacheDir, cacheDirCStr );

jni->DeleteLocalRef( cacheDir );
jni->DeleteLocalRef( classDef );

if( !retVal.empty() && retVal.back() != '/' )
retVal += "/";

app->activity->vm->DetachCurrentThread();

return retVal;
}

namespace Demo
{
struct AndroidAppController
Expand All @@ -59,26 +89,84 @@ namespace Demo
Ogre::uint64 mStartTime;
double mAccumulator;

bool mCriticalFailure;

AndroidAppController() :
mGraphicsGameState( 0 ),
mGraphicsSystem( 0 ),
mLogicGameState( 0 ),
mLogicSystem( 0 ),
mStartTime( 0 ),
mAccumulator( 0 )
mAccumulator( 0 ),
mCriticalFailure( false )
{
}

void init()
{
if( mCriticalFailure )
return;

if( !mGraphicsSystem )
{
MainEntryPoints::createSystems( &mGraphicsGameState, &mGraphicsSystem, &mLogicGameState,
&mLogicSystem );
mGraphicsSystem->initialize( MainEntryPoints::getWindowTitle() );
try
{
mGraphicsSystem->initialize( MainEntryPoints::getWindowTitle() );
}
catch( Ogre::RenderingAPIException &e )
{
ANativeActivity *nativeActivity = Demo::AndroidSystems::getAndroidApp()->activity;

JNIEnv *jni = 0;
nativeActivity->vm->AttachCurrentThread( &jni, nullptr );

jclass classDef = jni->GetObjectClass( nativeActivity->clazz );
jstring errorMsgJStr = jni->NewStringUTF( e.getDescription().c_str() );
jstring detailedErrorMsgJStr = jni->NewStringUTF( e.getFullDescription().c_str() );
jmethodID showNoVulkanAlertMethod = jni->GetMethodID(
classDef, "showNoVulkanAlert", "(Ljava/lang/String;Ljava/lang/String;)V" );
jni->CallVoidMethod( nativeActivity->clazz, showNoVulkanAlertMethod, errorMsgJStr,
detailedErrorMsgJStr );
jni->DeleteLocalRef( errorMsgJStr );
jni->DeleteLocalRef( detailedErrorMsgJStr );
jni->DeleteLocalRef( classDef );

// Let them leak. We can't do a clean shutdown. If we're here then there's
// nothing we can do. Let's just avoid crashing.
mLogicSystem = 0;
mGraphicsSystem = 0;

mCriticalFailure = true;

Demo::AndroidSystems::setNativeWindow( 0 );
nativeActivity->vm->DetachCurrentThread();
return;
}

if( mLogicSystem )
mLogicSystem->initialize();

{
// Disable Swappy if a previous run determined it was buggy.
struct stat buffer;
if( stat( ( Android_getCacheFolder() + "SwappyDisabled" ).c_str(), &buffer ) == 0 )
{
Ogre::LogManager::getSingleton().logMessage(
"Disabling Swappy Frame Pacing because previous runs determined it's buggy "
"on this "
"device.",
Ogre::LML_CRITICAL );

OGRE_ASSERT_HIGH( dynamic_cast<Ogre::VulkanRenderSystem *>(
mGraphicsSystem->getSceneManager()->getDestinationRenderSystem() ) );
Ogre::VulkanRenderSystem *renderSystem = static_cast<Ogre::VulkanRenderSystem *>(
mGraphicsSystem->getSceneManager()->getDestinationRenderSystem() );
renderSystem->setSwappyFramePacing( false );
}
}

mGraphicsSystem->createScene01();
if( mLogicSystem )
mLogicSystem->createScene01();
Expand Down Expand Up @@ -110,6 +198,17 @@ namespace Demo
Ogre::VulkanAndroidWindow *window =
static_cast<Ogre::VulkanAndroidWindow *>( windowBase );
window->setNativeWindow( 0 );

// Cache the fact that Swappy is buggy on this device, using an empty file.
OGRE_ASSERT_HIGH( dynamic_cast<Ogre::VulkanRenderSystem *>(
mGraphicsSystem->getSceneManager()->getDestinationRenderSystem() ) );
Ogre::VulkanRenderSystem *renderSystem = static_cast<Ogre::VulkanRenderSystem *>(
mGraphicsSystem->getSceneManager()->getDestinationRenderSystem() );
if( !renderSystem->getSwappyFramePacing() )
{
std::ofstream outFile( Android_getCacheFolder() + "SwappyDisabled",
std::ios::out | std::ios::binary );
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions Samples/2.0/AndroidAppTemplate/Template/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ buildscript {
google()
jcenter()
}
ext {
version_kotlin = '1.9.22'
}
dependencies {
classpath 'com.android.tools.build:gradle:8.0.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$version_kotlin"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
Expand Down

0 comments on commit cea0d20

Please sign in to comment.