瀏覽代碼

Add support for command line arguments on Android

Panagiotis Christopoulos Charitos 4 年之前
父節點
當前提交
00475c66a3
共有 6 個文件被更改,包括 206 次插入35 次删除
  1. 10 5
      AnKi/Config.h.cmake
  2. 34 5
      AnKi/Math/Mat.h
  3. 23 23
      AnKi/Util/File.cpp
  4. 6 2
      AnKi/Util/File.h
  5. 119 0
      AnKi/Util/System.cpp
  6. 14 0
      AnKi/Util/System.h

+ 10 - 5
AnKi/Config.h.cmake

@@ -208,11 +208,14 @@
 // Define the main() function.
 // Define the main() function.
 #if ANKI_OS_ANDROID
 #if ANKI_OS_ANDROID
 extern "C" {
 extern "C" {
-	struct android_app;
+struct android_app;
 }
 }
 
 
 namespace anki {
 namespace anki {
-	extern android_app* g_androidApp;
+extern android_app* g_androidApp;
+
+void* getAndroidCommandLineArguments(int& argc, char**& argv);
+void cleanupGetAndroidCommandLineArguments(void* ptr);
 }
 }
 
 
 #	define ANKI_MAIN_FUNCTION(myMain) \
 #	define ANKI_MAIN_FUNCTION(myMain) \
@@ -220,9 +223,11 @@ namespace anki {
 	extern "C" void android_main(android_app* app) \
 	extern "C" void android_main(android_app* app) \
 	{ \
 	{ \
 		anki::g_androidApp = app; \
 		anki::g_androidApp = app; \
-		char arr[] = "androidapp"; \
-		char* argv[] = {arr}; \
-		myMain(1, argv); \
+		char** argv; \
+		int argc; \
+		void* cleanupToken = anki::getAndroidCommandLineArguments(argc, argv); \
+		myMain(argc, argv); \
+		anki::cleanupGetAndroidCommandLineArguments(cleanupToken); \
 	}
 	}
 #else
 #else
 #	define ANKI_MAIN_FUNCTION(myMain) \
 #	define ANKI_MAIN_FUNCTION(myMain) \

+ 34 - 5
AnKi/Math/Mat.h

@@ -322,7 +322,11 @@ public:
 		TMat c;
 		TMat c;
 		for(U i = 0; i < J; i++)
 		for(U i = 0; i < J; i++)
 		{
 		{
+#if ANKI_SIMD_SSE
 			c.m_simd[i] = _mm_add_ps(m_simd[i], b.m_simd[i]);
 			c.m_simd[i] = _mm_add_ps(m_simd[i], b.m_simd[i]);
+#else
+			c.m_simd[i] = m_simd[i] + b.m_simd[i];
+#endif
 		}
 		}
 		return c;
 		return c;
 	}
 	}
@@ -342,7 +346,11 @@ public:
 	{
 	{
 		for(U i = 0; i < J; i++)
 		for(U i = 0; i < J; i++)
 		{
 		{
+#if ANKI_SIMD_SSE
 			m_simd[i] = _mm_add_ps(m_simd[i], b.m_simd[i]);
 			m_simd[i] = _mm_add_ps(m_simd[i], b.m_simd[i]);
+#else
+			m_simd[i] += b.m_simd[i];
+#endif
 		}
 		}
 		return *this;
 		return *this;
 	}
 	}
@@ -364,7 +372,11 @@ public:
 		TMat c;
 		TMat c;
 		for(U i = 0; i < J; i++)
 		for(U i = 0; i < J; i++)
 		{
 		{
+#if ANKI_SIMD_SSE
 			c.m_simd[i] = _mm_sub_ps(m_simd[i], b.m_simd[i]);
 			c.m_simd[i] = _mm_sub_ps(m_simd[i], b.m_simd[i]);
+#else
+			c.m_simd[i] = m_simd[i] - b.m_simd[i];
+#endif
 		}
 		}
 		return c;
 		return c;
 	}
 	}
@@ -384,7 +396,11 @@ public:
 	{
 	{
 		for(U i = 0; i < J; i++)
 		for(U i = 0; i < J; i++)
 		{
 		{
+#if ANKI_SIMD_SSE
 			m_simd[i] = _mm_sub_ps(m_simd[i], b.m_simd[i]);
 			m_simd[i] = _mm_sub_ps(m_simd[i], b.m_simd[i]);
+#else
+			m_simd[i] -= b.m_simd[i];
+#endif
 		}
 		}
 		return *this;
 		return *this;
 	}
 	}
@@ -412,11 +428,10 @@ public:
 	TMat operator*(const TMat& b) const
 	TMat operator*(const TMat& b) const
 	{
 	{
 		TMat out;
 		TMat out;
-#if ANKI_SIMD_SSE
 		const auto& m = *this;
 		const auto& m = *this;
-
 		for(U i = 0; i < 4; i++)
 		for(U i = 0; i < 4; i++)
 		{
 		{
+#if ANKI_SIMD_SSE
 			__m128 t1, t2;
 			__m128 t1, t2;
 
 
 			t1 = _mm_set1_ps(m(i, 0));
 			t1 = _mm_set1_ps(m(i, 0));
@@ -429,10 +444,21 @@ public:
 			t2 = _mm_add_ps(_mm_mul_ps(b.m_simd[3], t1), t2);
 			t2 = _mm_add_ps(_mm_mul_ps(b.m_simd[3], t1), t2);
 
 
 			out.m_simd[i] = t2;
 			out.m_simd[i] = t2;
-		}
 #else
 #else
-		ANKI_ASSERT(!"TODO");
+			float32x4_t t1, t2;
+
+			t1 = vmovq_n_f32(m(i, 0));
+			t2 = b.m_simd[0] * t1;
+			t1 = vmovq_n_f32(m(i, 1));
+			t2 = b.m_simd[1] * t1 + t2;
+			t1 = vmovq_n_f32(m(i, 2));
+			t2 = b.m_simd[2] * t1 + t2;
+			t1 = vmovq_n_f32(m(i, 3));
+			t2 = b.m_simd[3] * t1 + t2;
+
+			out.m_simd[i] = t2;
 #endif
 #endif
+		}
 
 
 		return out;
 		return out;
 	}
 	}
@@ -578,7 +604,10 @@ public:
 			_mm_store_ss(&out[i], _mm_dp_ps(m_simd[i], v.getSimd(), 0xF1));
 			_mm_store_ss(&out[i], _mm_dp_ps(m_simd[i], v.getSimd(), 0xF1));
 		}
 		}
 #else
 #else
-		ANKI_ASSERT(!"TODO");
+		for(U i = 0; i < J; i++)
+		{
+			out[i] = RowVec(m_simd[i]).dot(v);
+		}
 #endif
 #endif
 		return out;
 		return out;
 	}
 	}

+ 23 - 23
AnKi/Util/File.cpp

@@ -13,6 +13,9 @@
 #	include <android_native_app_glue.h>
 #	include <android_native_app_glue.h>
 #	include <android/asset_manager.h>
 #	include <android/asset_manager.h>
 #endif
 #endif
+#if ANKI_POSIX
+#	include <sys/stat.h>
+#endif
 
 
 namespace anki
 namespace anki
 {
 {
@@ -120,8 +123,22 @@ Error File::openCFile(const CString& filename, FileOpenFlag flags)
 	}
 	}
 
 
 	// Get file size
 	// Get file size
-	if(((flags & FileOpenFlag::READ) != FileOpenFlag::NONE) && !err)
+	if(!!(flags & FileOpenFlag::READ) && !err)
 	{
 	{
+#if ANKI_POSIX
+		const int fd = fileno(ANKI_CFILE);
+		struct stat stbuf;
+
+		if((fstat(fd, &stbuf) != 0) || (!S_ISREG(stbuf.st_mode)))
+		{
+			ANKI_UTIL_LOGE("fstat() failed");
+			err = Error::FUNCTION_FAILED;
+		}
+		else
+		{
+			m_size = stbuf.st_size;
+		}
+#else
 		fseek(ANKI_CFILE, 0, SEEK_END);
 		fseek(ANKI_CFILE, 0, SEEK_END);
 		I64 size = ftell(ANKI_CFILE);
 		I64 size = ftell(ANKI_CFILE);
 		if(size < 1)
 		if(size < 1)
@@ -131,9 +148,10 @@ Error File::openCFile(const CString& filename, FileOpenFlag flags)
 		}
 		}
 		else
 		else
 		{
 		{
-			m_size = U32(size);
+			m_size = PtrSize(size);
 			rewind(ANKI_CFILE);
 			rewind(ANKI_CFILE);
 		}
 		}
+#endif
 	}
 	}
 
 
 	return err;
 	return err;
@@ -169,6 +187,9 @@ Error File::openAndroidFile(const CString& filename, FileOpenFlag flags)
 
 
 	m_flags = flags;
 	m_flags = flags;
 
 
+	// Get size
+	m_size = AAsset_getLength(ANKI_AFILE);
+
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 #endif
 #endif
@@ -249,27 +270,6 @@ Error File::read(void* buff, PtrSize size)
 	return err;
 	return err;
 }
 }
 
 
-PtrSize File::getSize() const
-{
-	ANKI_ASSERT(m_file);
-	ANKI_ASSERT(m_flags != FileOpenFlag::NONE);
-	PtrSize out = 0;
-
-#if ANKI_OS_ANDROID
-	if(!!(m_flags & FileOpenFlag::SPECIAL))
-	{
-		out = AAsset_getLength(ANKI_AFILE);
-	}
-	else
-#endif
-	{
-		ANKI_ASSERT(m_size != 0);
-		out = m_size;
-	}
-
-	return out;
-}
-
 Error File::readU32(U32& out)
 Error File::readU32(U32& out)
 {
 {
 	ANKI_ASSERT(m_file);
 	ANKI_ASSERT(m_file);

+ 6 - 2
AnKi/Util/File.h

@@ -114,12 +114,16 @@ public:
 	PtrSize tell();
 	PtrSize tell();
 
 
 	/// The the size of the file.
 	/// The the size of the file.
-	PtrSize getSize() const;
+	PtrSize getSize() const
+	{
+		ANKI_ASSERT(!(m_flags & FileOpenFlag::WRITE));
+		return m_size;
+	}
 
 
 private:
 private:
 	void* m_file = nullptr; ///< A native file type
 	void* m_file = nullptr; ///< A native file type
 	FileOpenFlag m_flags = FileOpenFlag::NONE; ///< All the flags. Set on open
 	FileOpenFlag m_flags = FileOpenFlag::NONE; ///< All the flags. Set on open
-	U32 m_size = 0;
+	PtrSize m_size = 0;
 
 
 	/// Get the current machine's endianness
 	/// Get the current machine's endianness
 	static FileOpenFlag getMachineEndianness();
 	static FileOpenFlag getMachineEndianness();

+ 119 - 0
AnKi/Util/System.cpp

@@ -5,6 +5,7 @@
 
 
 #include <AnKi/Util/System.h>
 #include <AnKi/Util/System.h>
 #include <AnKi/Util/Logger.h>
 #include <AnKi/Util/Logger.h>
+#include <AnKi/Util/StringList.h>
 #include <cstdio>
 #include <cstdio>
 
 
 #if ANKI_POSIX
 #if ANKI_POSIX
@@ -22,6 +23,11 @@
 #	include <cstdlib>
 #	include <cstdlib>
 #endif
 #endif
 
 
+#if ANKI_OS_ANDROID
+#	include <android_native_app_glue.h>
+#	include <fcntl.h>
+#endif
+
 namespace anki
 namespace anki
 {
 {
 
 
@@ -93,4 +99,117 @@ std::tm getLocalTime()
 	return tm;
 	return tm;
 }
 }
 
 
+#if ANKI_OS_ANDROID
+/// Get the name of the apk. Doesn't use File to open files because /proc files are a bit special.
+static Error getAndroidApkName(StringAuto& name)
+{
+	const pid_t pid = getpid();
+
+	StringAuto path(name.getAllocator());
+	path.sprintf("/proc/%d/cmdline", pid);
+
+	const int fd = open(path.cstr(), O_RDONLY);
+	if(fd < 0)
+	{
+		ANKI_UTIL_LOGE("open() failed for: %s", path.cstr());
+		return Error::FUNCTION_FAILED;
+	}
+
+	Array<char, 128> tmp;
+	const ssize_t readBytes = read(fd, &tmp[0], sizeof(tmp));
+	if(readBytes < 0 || readBytes == 0)
+	{
+		close(fd);
+		ANKI_UTIL_LOGE("read() failed for: %s", path.cstr());
+		return Error::FUNCTION_FAILED;
+	}
+
+	name.create('?', readBytes);
+	memcpy(&name[0], &tmp[0], readBytes);
+
+	close(fd);
+	return Error::NONE;
+}
+
+void* getAndroidCommandLineArguments(int& argc, char**& argv)
+{
+	argc = 0;
+	argv = 0;
+
+	ANKI_ASSERT(g_androidApp);
+	JNIEnv* env;
+	g_androidApp->activity->vm->AttachCurrentThread(&env, NULL);
+
+	// Call getIntent().getStringExtra()
+	jobject me = g_androidApp->activity->clazz;
+
+	jclass acl = env->GetObjectClass(me); // class pointer of NativeActivity;
+	jmethodID giid = env->GetMethodID(acl, "getIntent", "()Landroid/content/Intent;");
+	jobject intent = env->CallObjectMethod(me, giid); // Got our intent
+
+	jclass icl = env->GetObjectClass(intent); // class pointer of Intent
+	jmethodID gseid = env->GetMethodID(icl, "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;");
+
+	jstring jsParam1 = static_cast<jstring>(env->CallObjectMethod(intent, gseid, env->NewStringUTF("cmd")));
+
+	// Parse the command line args
+	HeapAllocator<U8> alloc(allocAligned, nullptr);
+	StringListAuto args(alloc);
+
+	if(jsParam1)
+	{
+		const char* param1 = env->GetStringUTFChars(jsParam1, 0);
+		args.splitString(param1, ' ');
+		env->ReleaseStringUTFChars(jsParam1, param1);
+	}
+
+	// Add the apk name
+	StringAuto apkName(alloc);
+	if(!getAndroidApkName(apkName))
+	{
+		args.pushFront(apkName);
+	}
+	else
+	{
+		args.pushFront("unknown_apk");
+	}
+
+	// Allocate memory for all
+	U32 allStringsSize = 0;
+	for(const String& s : args)
+	{
+		allStringsSize += s.getLength() + 1;
+		++argc;
+	}
+
+	const PtrSize bufferSize = allStringsSize + sizeof(char*) * argc;
+	void* buffer = mallocAligned(bufferSize, ANKI_SAFE_ALIGNMENT);
+
+	// Set argv
+	argv = static_cast<char**>(buffer);
+
+	char* cbuffer = static_cast<char*>(buffer);
+	cbuffer += sizeof(char*) * argc;
+
+	U32 count = 0;
+	for(const String& s : args)
+	{
+		memcpy(cbuffer, &s[0], s.getLength() + 1);
+
+		argv[count++] = &cbuffer[0];
+
+		cbuffer += s.getLength() + 1;
+	}
+	ANKI_ASSERT(ptrToNumber(cbuffer) == ptrToNumber(buffer) + bufferSize);
+
+	return buffer;
+}
+
+void cleanupGetAndroidCommandLineArguments(void* ptr)
+{
+	ANKI_ASSERT(ptr);
+	freeAligned(ptr);
+}
+#endif
+
 } // end namespace anki
 } // end namespace anki

+ 14 - 0
AnKi/Util/System.h

@@ -36,6 +36,20 @@ Bool runningFromATerminal();
 
 
 /// Return the local time in a thread safe way.
 /// Return the local time in a thread safe way.
 std::tm getLocalTime();
 std::tm getLocalTime();
+
+#if ANKI_OS_ANDROID
+/// This function reads what is passed to "am" and interprets them as command line arguments. Should be called by
+/// android_main(). It's not thread safe. Don't call it more than once.
+/// Executing an apk using:
+/// @code
+/// adb shell am start XXX -e cmd "arg0 arg1 arg2"
+/// @endcode
+/// Whatever follows "cmd" will be a command line argument.
+ANKI_USE_RESULT void* getAndroidCommandLineArguments(int& argc, char**& argv);
+
+/// Takes the return value of getAndroidCommandLineArguments() for cleanup.
+void cleanupGetAndroidCommandLineArguments(void* ptr);
+#endif
 /// @}
 /// @}
 
 
 } // end namespace anki
 } // end namespace anki