Prechádzať zdrojové kódy

Rework the Android build

Panagiotis Christopoulos Charitos 3 rokov pred
rodič
commit
d340192702

+ 4 - 1
AnKi/Core/App.cpp

@@ -1,3 +1,4 @@
+
 // Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
 // All rights reserved.
 // Code licensed under the BSD License.
@@ -294,8 +295,10 @@ Error App::initInternal(CString executableFilename, AllocAlignedCallback allocCb
 	//
 #if !ANKI_OS_ANDROID
 	// Add the location of the executable where the shaders are supposed to be
+	StringAuto executableFname(m_heapAlloc);
+	ANKI_CHECK(getApplicationPath(executableFname));
 	StringAuto shadersPath(m_heapAlloc);
-	getParentFilepath(executableFilename, shadersPath);
+	getParentFilepath(executableFname, shadersPath);
 	shadersPath.append(":");
 	shadersPath.append(m_config->getRsrcDataPaths());
 	m_config->setRsrcDataPaths(shadersPath);

+ 0 - 1
AnKi/Resource/ConfigVars.defs.h

@@ -15,4 +15,3 @@ ANKI_CONFIG_VAR_STRING(RsrcDataPathExcludedStrings, "AndroidProject",
 ANKI_CONFIG_VAR_PTR_SIZE(RsrcTransferScratchMemorySize, 256_MB, 1_MB, 4_GB,
 						 "Memory that is used fot texture and buffer uploads")
 ANKI_CONFIG_VAR_BOOL(RsrcForceFullFpPrecision, false, "Force full floating point precision")
-ANKI_CONFIG_VAR_BOOL(RsrcRunMaliOfflineCompiler, false, "Will run the Mali offline compiler to gather some stats")

+ 37 - 75
AnKi/Resource/ResourceFilesystem.cpp

@@ -243,11 +243,6 @@ Error ResourceFilesystem::init(const ConfigSet& config, const CString& cacheDir)
 		return Error::USER_DATA;
 	}
 
-#if ANKI_OS_ANDROID
-	// Add the files of the .apk
-	ANKI_CHECK(addNewPath("APK package", excludedStrings, true));
-#endif
-
 	for(auto& path : paths)
 	{
 		ANKI_CHECK(addNewPath(path.toCString(), excludedStrings));
@@ -267,7 +262,7 @@ void ResourceFilesystem::addCachePath(const CString& path)
 	m_paths.emplaceBack(m_alloc, std::move(p));
 }
 
-Error ResourceFilesystem::addNewPath(const CString& filepath, const StringListAuto& excludedStrings, Bool special)
+Error ResourceFilesystem::addNewPath(const CString& filepath, const StringListAuto& excludedStrings)
 {
 	U32 fileCount = 0; // Count files manually because it's slower to get that number from the list
 	static const CString extension(".ankizip");
@@ -286,32 +281,7 @@ Error ResourceFilesystem::addNewPath(const CString& filepath, const StringListAu
 
 	PtrSize pos;
 	Path path;
-	if(special)
-	{
-		// Android apk, read the file that contains the directory structure
-
-		// Read the file
-		File dirStructure;
-		ANKI_CHECK(dirStructure.open("DirStructure.txt", FileOpenFlag::READ | FileOpenFlag::SPECIAL));
-		StringAuto txt(m_alloc);
-		ANKI_CHECK(dirStructure.readAllText(txt));
-
-		StringListAuto filenames(m_alloc);
-		filenames.splitString(txt, '\n');
-
-		// Create the Path
-		for(const String& filename : filenames)
-		{
-			if(!rejectPath(filename))
-			{
-				path.m_files.pushBack(m_alloc, filename);
-				++fileCount;
-			}
-		}
-
-		path.m_isSpecial = true;
-	}
-	else if((pos = filepath.find(extension)) != CString::NPOS && pos == filepath.getLength() - extension.getLength())
+	if((pos = filepath.find(extension)) != CString::NPOS && pos == filepath.getLength() - extension.getLength())
 	{
 		// It's an archive
 
@@ -396,8 +366,26 @@ Error ResourceFilesystem::addNewPath(const CString& filepath, const StringListAu
 
 Error ResourceFilesystem::openFile(const ResourceFilename& filename, ResourceFilePtr& filePtr)
 {
-	ResourceFile* rfile = nullptr;
-	Error err = Error::NONE;
+	ResourceFile* rfile;
+	Error err = openFileInternal(filename, rfile);
+
+	if(err)
+	{
+		ANKI_RESOURCE_LOGE("Resource file not found: %s", filename.cstr());
+		m_alloc.deleteInstance(rfile);
+	}
+	else
+	{
+		ANKI_ASSERT(rfile);
+		filePtr.reset(rfile);
+	}
+
+	return err;
+}
+
+Error ResourceFilesystem::openFileInternal(const ResourceFilename& filename, ResourceFile*& rfile)
+{
+	rfile = nullptr;
 
 	// Search for the fname in reverse order
 	for(const Path& p : m_paths)
@@ -415,7 +403,7 @@ Error ResourceFilesystem::openFile(const ResourceFilename& filename, ResourceFil
 				CResourceFile* file = m_alloc.newInstance<CResourceFile>(m_alloc);
 				rfile = file;
 
-				err = file->m_file.open(&newFname[0], FileOpenFlag::READ);
+				ANKI_CHECK(file->m_file.open(&newFname[0], FileOpenFlag::READ));
 			}
 		}
 		else
@@ -435,30 +423,16 @@ Error ResourceFilesystem::openFile(const ResourceFilename& filename, ResourceFil
 					ZipResourceFile* file = m_alloc.newInstance<ZipResourceFile>(m_alloc);
 					rfile = file;
 
-					err = file->open(p.m_path.toCString(), filename);
+					ANKI_CHECK(file->open(p.m_path.toCString(), filename));
 				}
 				else
 				{
 					StringAuto newFname(m_alloc);
-					if(!p.m_isSpecial)
-					{
-						newFname.sprintf("%s/%s", &p.m_path[0], &filename[0]);
-					}
-					else
-					{
-						newFname.sprintf("%s", &filename[0]);
-					}
+					newFname.sprintf("%s/%s", &p.m_path[0], &filename[0]);
 
 					CResourceFile* file = m_alloc.newInstance<CResourceFile>(m_alloc);
 					rfile = file;
-
-					FileOpenFlag fopenFlags = FileOpenFlag::READ;
-					if(p.m_isSpecial)
-					{
-						fopenFlags |= FileOpenFlag::SPECIAL;
-					}
-
-					err = file->m_file.open(&newFname[0], fopenFlags);
+					ANKI_CHECK(file->m_file.open(newFname, FileOpenFlag::READ));
 
 #if 0
 					printf("Opening asset %s\n", &newFname[0]);
@@ -473,37 +447,25 @@ Error ResourceFilesystem::openFile(const ResourceFilename& filename, ResourceFil
 		}
 	} // end for all paths
 
-	if(err)
-	{
-		m_alloc.deleteInstance(rfile);
-		return err;
-	}
-
-	// File not found? Try to find it outside the resource dirs
-	if(!rfile && fileExists(filename))
+	// File not found? On Win/Linux try to find it outside the resource dirs. On Android try the archive
+	if(!rfile)
 	{
 		CResourceFile* file = m_alloc.newInstance<CResourceFile>(m_alloc);
-		err = file->m_file.open(filename, FileOpenFlag::READ);
-		if(err)
-		{
-			m_alloc.deleteInstance(file);
-			return err;
-		}
-
 		rfile = file;
+
+		FileOpenFlag openFlags = FileOpenFlag::READ;
+#if ANKI_OS_ANDROID
+		openFlags |= FileOpenFlag::SPECIAL;
+#endif
+		ANKI_CHECK(file->m_file.open(filename, openFlags));
+
+#if !ANKI_OS_ANDROID
 		ANKI_RESOURCE_LOGW(
 			"Loading resource outside the resource paths/archives. This is only OK for tools and debugging: %s",
 			filename.cstr());
+#endif
 	}
 
-	if(!rfile)
-	{
-		ANKI_RESOURCE_LOGE("File not found: %s", &filename[0]);
-		return Error::USER_DATA;
-	}
-
-	// Done
-	filePtr.reset(rfile);
 	return Error::NONE;
 }
 

+ 3 - 3
AnKi/Resource/ResourceFilesystem.h

@@ -118,7 +118,6 @@ private:
 		String m_path; ///< A directory or an archive.
 		Bool m_isArchive = false;
 		Bool m_isCache = false;
-		Bool m_isSpecial = false;
 
 		Path() = default;
 
@@ -137,7 +136,6 @@ private:
 			m_path = std::move(b.m_path);
 			m_isArchive = b.m_isArchive;
 			m_isCache = b.m_isCache;
-			m_isSpecial = b.m_isSpecial;
 			return *this;
 		}
 	};
@@ -147,7 +145,9 @@ private:
 	String m_cacheDir;
 
 	/// Add a filesystem path or an archive. The path is read-only.
-	ANKI_USE_RESULT Error addNewPath(const CString& path, const StringListAuto& excludedStrings, Bool special = false);
+	ANKI_USE_RESULT Error addNewPath(const CString& path, const StringListAuto& excludedStrings);
+
+	ANKI_USE_RESULT Error openFileInternal(const ResourceFilename& filename, ResourceFile*& rfile);
 
 	void addCachePath(const CString& path);
 };

+ 0 - 16
AnKi/Resource/ShaderProgramResource.cpp

@@ -386,22 +386,6 @@ void ShaderProgramResource::initVariant(const ShaderProgramResourceVariantInitIn
 			inf.m_constValues.setArray((constValueCount) ? constValues.getBegin() : nullptr, constValueCount);
 			ShaderPtr shader = getManager().getGrManager().newShader(inf);
 
-			if(getConfig().getRsrcRunMaliOfflineCompiler() && (ANKI_OS_LINUX || ANKI_OS_WINDOWS))
-			{
-				MaliOfflineCompilerOut maliocOut;
-				const Error err =
-					runMaliOfflineCompiler(ANKI_SOURCE_DIRECTORY "/ThirdParty/Bin/MaliOfflineCompiler/malioc",
-										   binary.m_codeBlocks[binaryVariant->m_codeBlockIndices[shaderType]].m_binary,
-										   inf.m_shaderType, getAllocator(), maliocOut);
-
-				if(!err)
-				{
-					StringAuto maliocOutStr(getAllocator());
-					maliocOut.toString(maliocOutStr);
-					ANKI_RESOURCE_LOGI("Mali offline compiler: %s: %s", cprogName, maliocOutStr.cstr());
-				}
-			}
-
 			const ShaderTypeBit shaderBit = ShaderTypeBit(1 << shaderType);
 			if(!!(shaderBit & ShaderTypeBit::ALL_GRAPHICS))
 			{

+ 4 - 4
AnKi/ShaderCompiler/ShaderProgramParser.cpp

@@ -24,7 +24,7 @@ static const char SHADER_HEADER[] = R"(#version 460 core
 #define ANKI_PLATFORM_MOBILE %d
 #define ANKI_FORCE_FULL_FP_PRECISION %d
 
-#define _ANKI_SUPPORTS_64BIT !ANKI_PLATFORM_MOBILE
+#define ANKI_SUPPORTS_64BIT !ANKI_PLATFORM_MOBILE
 
 #define gl_VertexID gl_VertexIndex
 
@@ -53,7 +53,7 @@ static const char SHADER_HEADER[] = R"(#version 460 core
 #extension GL_EXT_shader_explicit_arithmetic_types_float16 : enable
 #extension GL_EXT_shader_explicit_arithmetic_types_float32 : enable
 
-#if _ANKI_SUPPORTS_64BIT
+#if ANKI_SUPPORTS_64BIT
 #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable
 #extension GL_EXT_shader_explicit_arithmetic_types_float64 : enable
 #extension GL_EXT_shader_atomic_int64 : enable
@@ -150,7 +150,7 @@ static const char SHADER_HEADER[] = R"(#version 460 core
 #define IVec4 ivec4
 #define _ANKI_SIZEOF_ivec4 16u
 
-#if _ANKI_SUPPORTS_64BIT
+#if ANKI_SUPPORTS_64BIT
 #	define U64 uint64_t
 #	define _ANKI_SIZEOF_uint64_t 8u
 #	define U64Vec2 u64vec2
@@ -181,7 +181,7 @@ static const char SHADER_HEADER[] = R"(#version 460 core
 
 #define Bool bool
 
-#if _ANKI_SUPPORTS_64BIT
+#if ANKI_SUPPORTS_64BIT
 #	define Address U64
 #else
 #	define Address UVec2

+ 39 - 5
AnKi/Shaders/CMakeLists.txt

@@ -5,6 +5,30 @@ file(GLOB_RECURSE header_fnames *.h)
 ProcessorCount(proc_count)
 MATH(EXPR proc_count "${proc_count}-1")
 
+if(ANKI_OVERRIDE_SHADER_COMPILER STREQUAL "")
+	set(shader_compiler_bin "ShaderCompiler")
+	set(shader_compiler_dep "ShaderCompiler")
+else()
+	set(shader_compiler_bin ${ANKI_OVERRIDE_SHADER_COMPILER})
+	set(shader_compiler_dep "")
+endif()
+
+set(out_dir "${CMAKE_BINARY_DIR}/Bin/ShaderBinaries")
+
+if(ANDROID OR ARM)
+	message("++ Compiling shaders for mobile")
+	set(extra_compiler_args "-mobile-platform")
+else()
+	message("++ Compiling shaders for desktop")
+endif()
+
+if(ANKI_SHADER_FULL_PRECISION)
+	message("++ Forcing full shader precision")
+	set(extra_compiler_args ${extra_compiler_args} "-force-full-fp")
+else()
+	message("++ Leaving default shader precision")
+endif()
+
 foreach(prog_fname ${prog_fnames})
 	get_filename_component(filename ${prog_fname} NAME)
 	set(bin_fname ${CMAKE_CURRENT_BINARY_DIR}/${filename}bin)
@@ -14,8 +38,8 @@ foreach(prog_fname ${prog_fnames})
 
 	add_custom_command(
 		OUTPUT ${bin_fname}
-		COMMAND ShaderCompiler -o ${bin_fname} -j ${proc_count} -I "${CMAKE_CURRENT_SOURCE_DIR}/../.." ${prog_fname}
-		DEPENDS ShaderCompiler ${prog_fname} ${glsl_fnames} ${header_fnames}
+		COMMAND ${shader_compiler_bin} -o ${bin_fname} -j ${proc_count} -I "${CMAKE_CURRENT_SOURCE_DIR}/../.." ${extra_compiler_args} ${prog_fname}
+		DEPENDS ${shader_compiler_dep} ${prog_fname} ${glsl_fnames} ${header_fnames}
 		COMMENT "Build ${prog_fname}")
 
 	add_custom_target(
@@ -24,10 +48,20 @@ foreach(prog_fname ${prog_fnames})
 
 	add_custom_command(
 		TARGET ${target_name} POST_BUILD
-		COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/Bin/ShaderBinaries
-		COMMAND ${CMAKE_COMMAND} -E copy ${bin_fname} ${CMAKE_BINARY_DIR}/Bin/ShaderBinaries)
+		COMMAND ${CMAKE_COMMAND} -E make_directory ${out_dir}
+		COMMAND ${CMAKE_COMMAND} -E copy ${bin_fname} ${out_dir})
 
 	list(APPEND program_targets ${target_name})
 endforeach()
 
-add_custom_target(AnKiShaders DEPENDS ${program_targets})
+add_custom_target(AnKiShaders ALL DEPENDS ${program_targets})
+
+# Create link of shader bin dir to the android assets
+if(ANDROID)
+	set(assets_dir "${CMAKE_BINARY_DIR}/../../../../../assets/ShaderBinaries")
+
+	add_custom_command(
+		TARGET AnKiShaders POST_BUILD
+		COMMAND ${CMAKE_COMMAND} -E create_symlink ${out_dir} ${assets_dir}
+	)
+endif()

+ 3 - 1
AnKi/Shaders/RtShadowsHit.ankiprog

@@ -27,12 +27,14 @@ layout(location = 0) rayPayloadInEXT F32 g_payload;
 
 hitAttributeEXT vec2 g_attribs;
 
+#if ALPHA_TEXTURE == 1 && ANKI_SUPPORTS_64BIT
 ANKI_DEFINE_LOAD_STORE(U16Vec3, 2)
 ANKI_DEFINE_LOAD_STORE(MainVertex, ANKI_ALIGNOF(MainVertex))
+#endif
 
 void main()
 {
-#if ALPHA_TEXTURE == 1
+#if ALPHA_TEXTURE == 1 && ANKI_SUPPORTS_64BIT
 	const ModelGpuDescriptor model = u_modelDescriptor;
 	const MeshGpuDescriptor mesh = model.m_mesh;
 

+ 16 - 3
AnKi/Util/Filesystem.cpp

@@ -9,7 +9,7 @@ namespace anki {
 
 void getFilepathExtension(const CString& filename, StringAuto& out)
 {
-	const char* pc = std::strrchr(filename.cstr(), '.');
+	const Char* pc = std::strrchr(filename.cstr(), '.');
 
 	if(pc == nullptr)
 	{
@@ -27,7 +27,13 @@ void getFilepathExtension(const CString& filename, StringAuto& out)
 
 void getFilepathFilename(const CString& filename, StringAuto& out)
 {
-	const char* pc = std::strrchr(filename.cstr(), '/');
+	const Char* pc1 = std::strrchr(filename.cstr(), '/');
+#if ANKI_OS_WINDOWS
+	const Char* pc2 = std::strrchr(filename.cstr(), '\\');
+#else
+	const Char* pc2 = pc1;
+#endif
+	const Char* pc = (pc1 > pc2) ? pc1 : pc2;
 
 	if(pc == nullptr)
 	{
@@ -45,7 +51,14 @@ void getFilepathFilename(const CString& filename, StringAuto& out)
 
 void getParentFilepath(const CString& filename, StringAuto& out)
 {
-	const char* pc = std::strrchr(filename.cstr(), '/');
+	const Char* pc1 = std::strrchr(filename.cstr(), '/');
+#if ANKI_OS_WINDOWS
+	const Char* pc2 = std::strrchr(filename.cstr(), '\\');
+#else
+	const Char* pc2 = pc1;
+#endif
+
+	const Char* pc = (pc1 > pc2) ? pc1 : pc2;
 
 	if(pc == nullptr)
 	{

+ 3 - 0
AnKi/Util/Filesystem.h

@@ -74,6 +74,9 @@ ANKI_USE_RESULT Error getTempDirectory(StringAuto& out);
 /// Get the time the file was last modified.
 ANKI_USE_RESULT Error getFileModificationTime(CString filename, U32& year, U32& month, U32& day, U32& hour, U32& min,
 											  U32& second);
+
+/// Get the path+filename of the currently running executable.
+ANKI_USE_RESULT Error getApplicationPath(StringAuto& path);
 /// @}
 
 } // end namespace anki

+ 24 - 0
AnKi/Util/FilesystemPosix.cpp

@@ -19,6 +19,7 @@
 #include <ftw.h> // For walkDirectoryTree
 #include <cstdlib>
 #include <time.h>
+#include <unistd.h>
 #if ANKI_OS_ANDROID
 #	include <android_native_app_glue.h>
 #endif
@@ -243,4 +244,27 @@ Error getFileModificationTime(CString filename, U32& year, U32& month, U32& day,
 	return Error::NONE;
 }
 
+Error getApplicationPath(StringAuto& out)
+{
+#if ANKI_OS_ANDROID
+	ANKI_ASSERT(0 && "getApplicationPath() doesn't work on Android");
+#else
+	DynamicArrayAuto<Char> buff(out.getAllocator(), 1024);
+
+	const ssize_t result = readlink("/proc/self/exe", &buff[0], buff.getSize());
+	if(result < 0)
+	{
+		ANKI_UTIL_LOGE("readlink() failed");
+		return Error::FUNCTION_FAILED;
+	}
+
+	out.destroy();
+	out.create('0', result);
+
+	memcpy(&out[0], &buff[0], result);
+#endif
+
+	return Error::NONE;
+}
+
 } // end namespace anki

+ 20 - 0
AnKi/Util/FilesystemWindows.cpp

@@ -197,4 +197,24 @@ Error walkDirectoryTreeInternal(const CString& dir, const Function<Error(const C
 	return walkDirectoryTreeRecursive(dir, callback, baseDirLen);
 }
 
+Error getApplicationPath(StringAuto& out)
+{
+	DynamicArrayAuto<Char> buff(out.getAllocator(), 1024);
+
+	const DWORD result = GetModuleFileNameA(nullptr, &buff[0], buff.getSize());
+	DWORD lastError = GetLastError();
+	if(result == 0
+	   || (result == buff.getSize() && (lastError == ERROR_INSUFFICIENT_BUFFER || lastError == ERROR_SUCCESS)))
+	{
+		ANKI_UTIL_LOGE("GetModuleFileNameA() failed");
+		return Error::FUNCTION_FAILED;
+	}
+
+	out.destroy();
+	out.create('0', result);
+
+	memcpy(&out[0], &buff[0], result);
+	return Error::NONE;
+}
+
 } // end namespace anki

+ 10 - 1
AnKi/Util/Win32Minimal.h

@@ -45,6 +45,8 @@ typedef void* LPVOID;
 typedef const CHAR *LPCSTR, *PCSTR;
 typedef const CHAR* PCZZSTR;
 typedef CHAR* LPSTR;
+typedef struct HINSTANCE__* HINSTANCE;
+typedef HINSTANCE HMODULE;
 ANKI_DECLARE_HANDLE(HWND);
 
 typedef struct _SECURITY_ATTRIBUTES SECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
@@ -112,6 +114,7 @@ ANKI_WINBASEAPI BOOL ANKI_WINAPI GetConsoleScreenBufferInfo(HANDLE hConsoleOutpu
 															PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo);
 ANKI_WINBASEAPI BOOL ANKI_WINAPI SetConsoleTextAttribute(HANDLE hConsoleOutput, WORD wAttributes);
 ANKI_WINBASEAPI VOID ANKI_WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo);
+ANKI_WINBASEAPI DWORD GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize);
 
 #undef ANKI_WINBASEAPI
 #undef ANKI_DECLARE_HANDLE
@@ -136,7 +139,8 @@ constexpr WORD CSIDL_PROFILE = 0x0028;
 constexpr DWORD STD_OUTPUT_HANDLE = (DWORD)-11;
 constexpr HRESULT S_OK = 0;
 constexpr DWORD INFINITE = 0xFFFFFFFF;
-
+constexpr DWORD ERROR_INSUFFICIENT_BUFFER = 122l;
+constexpr DWORD ERROR_SUCCESS = 0;
 constexpr WORD FOREGROUND_BLUE = 0x0001;
 constexpr WORD FOREGROUND_GREEN = 0x0002;
 constexpr WORD FOREGROUND_RED = 0x0004;
@@ -436,4 +440,9 @@ inline VOID GetSystemInfo(LPSYSTEM_INFO lpSystemInfo)
 	::GetSystemInfo(reinterpret_cast<::LPSYSTEM_INFO>(lpSystemInfo));
 }
 
+inline DWORD GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize)
+{
+	return ::GetModuleFileNameA(hModule, lpFilename, nSize);
+}
+
 } // end namespace anki

+ 2 - 0
CMakeLists.txt

@@ -123,6 +123,8 @@ endif()
 option(ANKI_SIMD "Enable SIMD optimizations" ON)
 option(ANKI_ADDRESS_SANITIZER "Enable address sanitizer (-fsanitize=address)" OFF)
 option(ANKI_HEADLESS "Build a headless application" OFF)
+option(ANKI_SHADER_FULL_PRECISION "Build shaders with full precision" OFF)
+set(ANKI_OVERRIDE_SHADER_COMPILER "" CACHE FILEPATH "Set the ShaderCompiler to be used to compile all shaders")
 
 # Take a wild guess on the windowing system
 if(ANKI_HEADLESS)

+ 8 - 4
README.md

@@ -90,17 +90,21 @@ Prerequisites:
 
 - Android Studio
 - From Android Studio's package manager you need to install `NDK` and `CMake`
+- Having built AnKi for your host operating system (Linux or Windows)
 
-Android builds work a bit differently from Linux and Windows. You are required to generate a gradle project per build
-target. For example, if you want to generate a project for the `Sponza` sample just type from a Linux terminal:
+Android builds work a bit differently from Linux and Windows. First you need to have built AnKi for your host operating
+system. That's because Android builds requires the `ShaderCompiler/ShaderCompiler.exe` to compile the shaders for
+Android. Then you have to generate a gradle project per build target.
+
+For example, if you want to generate a project for the `Sponza` sample just type from a Linux terminal:
 
 	$cd path/to/anki
-	$./Samples/Sponza/GenerateAndroidProject.sh
+	$./Samples/Sponza/GenerateAndroidProject.sh path/to/Bin/ShaderCompiler
 
 or from a PowerShell terminal on Windows:
 
 	$cd path/to/anki
-	$./Samples/Sponza/GenerateAndroidProject.bat
+	$./Samples/Sponza/GenerateAndroidProject.bat path/to/Bin/ShaderCompiler.exe
 
 The `GenerateAndroidProject` scripts will generate a project in the root directory of AnKi. So for the `Sponza` sample
 the script will create a directory named `AndroidProject_Sponza`.

+ 6 - 3
Samples/Sponza/GenerateAndroidProject.sh

@@ -1,5 +1,8 @@
 #!/bin/bash
 
-SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
-cd $SCRIPT_DIR
-../../Tools/Android/GenerateAndroidProject.py -o ../.. -t Sponza -a ./Assets/
+if [ "$#" -ne 1 ]; then
+    echo "Usage: ${0} <path to ShaderCompiler>"
+	exit 0
+fi
+
+./Tools/Android/GenerateAndroidProject.py -o . -t Sponza -a ./Samples/Sponza/Assets/ --shader-compiler $1

+ 9 - 22
Tools/Android/GenerateAndroidProject.py

@@ -16,6 +16,7 @@ class Context:
     target = ""
     asserts_dir = None
     out_dir = ""
+    shader_compiler = ""
 
 
 def parse_commandline():
@@ -26,10 +27,15 @@ def parse_commandline():
     parser.add_option("-o", "--out-dir", dest="out_dir", type="string", help="Where to create the project")
     parser.add_option("-t", "--target", dest="target", type="string", help="The name of .so to package")
     parser.add_option("-a", "--assets", dest="assets", type="string", help="Assets directory")
+    parser.add_option("-c",
+                      "--shader-compiler",
+                      dest="shader_compiler",
+                      type="string",
+                      help="The path of the shader compiler")
 
     (options, args) = parser.parse_args()
 
-    required = "target out_dir".split()
+    required = "target out_dir shader_compiler".split()
     for r in required:
         if options.__dict__[r] is None:
             parser.print_help()
@@ -40,6 +46,7 @@ def parse_commandline():
     if options.assets is not None:
         ctx.asserts_dir = os.path.abspath(options.assets)
     ctx.out_dir = os.path.abspath(options.out_dir)
+    ctx.shader_compiler = os.path.abspath(options.shader_compiler)
 
     return ctx
 
@@ -74,34 +81,13 @@ def main():
     assets_dir = os.path.join(project_dir, "assets")
     if not os.path.isdir(assets_dir):
         os.mkdir(assets_dir)
-        os.mkdir(os.path.join(project_dir, "assets/AnKi/"))
-        os.symlink(os.path.join(this_script_dir, "../../AnKi/Shaders"),
-                   os.path.join(project_dir, "assets/AnKi/Shaders"))
         os.symlink(os.path.join(this_script_dir, "../../EngineAssets"),
                    os.path.join(project_dir, "assets/EngineAssets"))
-        os.mkdir(os.path.join(project_dir, "assets/ThirdParty/"))
-        os.symlink(os.path.join(this_script_dir, "../../ThirdParty/FidelityFX"),
-                   os.path.join(project_dir, "assets/ThirdParty/FidelityFX"))
         if ctx.asserts_dir is not None:
             os.symlink(ctx.asserts_dir, os.path.join(project_dir, "assets/Assets"))
     else:
         print("Asset directory (%s) already exists. Skipping" % assets_dir)
 
-    # Write the asset directory structure to a file
-    dir_structure_file = open(os.path.join(assets_dir, "DirStructure.txt"), "w", newline="\n")
-    for root, dirs, files in os.walk(assets_dir, followlinks=True):
-        for f in files:
-            if f.find("DirStructure.txt") >= 0:
-                continue
-
-            filename = os.path.join(root, f)
-            filename = filename.replace(assets_dir, "")
-            filename = filename.replace("\\", "/")
-            if filename[0] == '/':
-                filename = filename[1:]
-            dir_structure_file.write("%s\n" % filename)
-    dir_structure_file.close()
-
     # strings.xml
     replace_in_file(os.path.join(project_dir, "app/src/main/res/values/strings.xml"), "%APP_NAME%", ctx.target)
 
@@ -109,6 +95,7 @@ def main():
     build_gradle = os.path.join(project_dir, "app/build.gradle")
     replace_in_file(build_gradle, "%TARGET%", ctx.target)
     replace_in_file(build_gradle, "%PYTHON%", sys.executable)
+    replace_in_file(build_gradle, "%COMPILER%", ctx.shader_compiler)
     replace_in_file(build_gradle, "%CMAKE%", os.path.join(this_script_dir, "../../CMakeLists.txt"))
 
     # Manifest

+ 6 - 4
Tools/Android/app/build.gradle

@@ -20,9 +20,10 @@ android {
                             "-DCMAKE_BUILD_TYPE=Debug",
                             "-DANKI_EXTRA_CHECKS=ON",
                             "-DANKI_BUILD_TESTS=ON",
-                            "-DPYTHON_EXECUTABLE:FILEPATH=%PYTHON%"
+                            "-DPYTHON_EXECUTABLE:FILEPATH=%PYTHON%",
+                            "-DANKI_OVERRIDE_SHADER_COMPILER:FILEPATH=%COMPILER%"
                     version "3.12+"
-                    targets "%TARGET%"
+                    targets "%TARGET%", "AnKiShaders"
                 }
             }
 
@@ -39,9 +40,10 @@ android {
                             "-DCMAKE_BUILD_TYPE=Release",
                             "-DANKI_EXTRA_CHECKS=OFF",
                             "-DANKI_BUILD_TESTS=ON",
-                            "-DPYTHON_EXECUTABLE:FILEPATH=%PYTHON%"
+                            "-DPYTHON_EXECUTABLE:FILEPATH=%PYTHON%",
+                            "-DANKI_OVERRIDE_SHADER_COMPILER:FILEPATH=%COMPILER%"
                     version "3.12+"
-                    targets "%TARGET%"
+                    targets "%TARGET%", "AnKiShaders"
                 }
             }