1
0
forked from 0ad/0ad

Partial Android compatibility.

Remove unnecessary VM allocation (which seemingly causes problems on
Android due to mmap during static initialization).
Allow building without NVTT.

This was SVN commit r11074.
This commit is contained in:
Ykkrosh 2012-02-15 13:58:58 +00:00
parent c63d06d59f
commit f4625e69af
13 changed files with 145 additions and 8 deletions

View File

@ -29,6 +29,8 @@
#include "ps/Profiler2.h" #include "ps/Profiler2.h"
#include "ps/XML/Xeromyces.h" #include "ps/XML/Xeromyces.h"
#if CONFIG2_NVTT
#include "nvtt/nvtt.h" #include "nvtt/nvtt.h"
/** /**
@ -76,6 +78,8 @@ struct CTextureConverter::ConversionResult
bool ret; // true if the conversion succeeded bool ret; // true if the conversion succeeded
}; };
#endif // CONFIG2_NVTT
void CTextureConverter::Settings::Hash(MD5& hash) void CTextureConverter::Settings::Hash(MD5& hash)
{ {
hash.Update((const u8*)&format, sizeof(format)); hash.Update((const u8*)&format, sizeof(format));
@ -273,7 +277,9 @@ CTextureConverter::CTextureConverter(PIVFS vfs, bool highQuality) :
{ {
// Verify that we are running with at least the version we were compiled with, // Verify that we are running with at least the version we were compiled with,
// to avoid bugs caused by ABI changes // to avoid bugs caused by ABI changes
#if CONFIG2_NVTT
ENSURE(nvtt::version() >= NVTT_VERSION); ENSURE(nvtt::version() >= NVTT_VERSION);
#endif
// Set up the worker thread: // Set up the worker thread:
@ -355,6 +361,8 @@ bool CTextureConverter::ConvertTexture(const CTexturePtr& texture, const VfsPath
} }
} }
#if CONFIG2_NVTT
shared_ptr<ConversionRequest> request(new ConversionRequest); shared_ptr<ConversionRequest> request(new ConversionRequest);
request->dest = dest; request->dest = dest;
request->texture = texture; request->texture = texture;
@ -428,10 +436,16 @@ bool CTextureConverter::ConvertTexture(const CTexturePtr& texture, const VfsPath
SDL_SemPost(m_WorkerSem); SDL_SemPost(m_WorkerSem);
return true; return true;
#else
LOGERROR(L"Failed to convert texture \"%ls\" (NVTT not available)", src.string().c_str());
return false;
#endif
} }
bool CTextureConverter::Poll(CTexturePtr& texture, VfsPath& dest, bool& ok) bool CTextureConverter::Poll(CTexturePtr& texture, VfsPath& dest, bool& ok)
{ {
#if CONFIG2_NVTT
shared_ptr<ConversionResult> result; shared_ptr<ConversionResult> result;
// Grab the first result (if any) // Grab the first result (if any)
@ -473,6 +487,10 @@ bool CTextureConverter::Poll(CTexturePtr& texture, VfsPath& dest, bool& ok)
dest = result->dest; dest = result->dest;
ok = true; ok = true;
return true; return true;
#else // #if CONFIG2_NVTT
return false;
#endif
} }
bool CTextureConverter::IsBusy() bool CTextureConverter::IsBusy()
@ -491,6 +509,8 @@ void* CTextureConverter::RunThread(void* data)
CTextureConverter* textureConverter = static_cast<CTextureConverter*>(data); CTextureConverter* textureConverter = static_cast<CTextureConverter*>(data);
#if CONFIG2_NVTT
// Wait until the main thread wakes us up // Wait until the main thread wakes us up
while (SDL_SemWait(textureConverter->m_WorkerSem) == 0) while (SDL_SemWait(textureConverter->m_WorkerSem) == 0)
{ {
@ -541,5 +561,7 @@ void* CTextureConverter::RunThread(void* data)
pthread_mutex_unlock(&textureConverter->m_WorkerMutex); pthread_mutex_unlock(&textureConverter->m_WorkerMutex);
} }
#endif
return NULL; return NULL;
} }

View File

@ -54,7 +54,11 @@ template<class T> class OverrunProtector
NONCOPYABLE(OverrunProtector); // const member NONCOPYABLE(OverrunProtector); // const member
public: public:
OverrunProtector() OverrunProtector()
#if CONFIG2_ALLOCATORS_OVERRUN_PROTECTION
: object(new(vm::Allocate(sizeof(T))) T()) : object(new(vm::Allocate(sizeof(T))) T())
#else
: object(new T())
#endif
{ {
lock(); lock();
} }
@ -62,8 +66,12 @@ public:
~OverrunProtector() ~OverrunProtector()
{ {
unlock(); unlock();
#if CONFIG2_ALLOCATORS_OVERRUN_PROTECTION
object->~T(); // call dtor (since we used placement new) object->~T(); // call dtor (since we used placement new)
vm::Free(object, sizeof(T)); vm::Free(object, sizeof(T));
#else
delete object;
#endif
} }
T* get() const T* get() const

View File

@ -110,4 +110,9 @@
# define CONFIG2_AUDIO 1 # define CONFIG2_AUDIO 1
#endif #endif
// allow use of NVTT
#ifndef CONFIG2_NVTT
# define CONFIG2_NVTT 1
#endif
#endif // #ifndef INCLUDED_CONFIG2 #endif // #ifndef INCLUDED_CONFIG2

View File

@ -225,10 +225,15 @@ bool ogl_HaveVersion(const char* desired_version)
return false; return false;
} }
// guaranteed to be of the form major.minor[.release]. // guaranteed to be of the form "major.minor[.release][ vendor-specific]"
// or "OpenGL ES major.minor[.release][ vendor-specific]".
// we won't distinguish GLES 2.0 from GL 2.0, but that's okay since
// they're close enough.
const char* version = (const char*)glGetString(GL_VERSION); const char* version = (const char*)glGetString(GL_VERSION);
int major, minor; int major, minor;
if(!version || sscanf_s(version, "%d.%d", &major, &minor) != 2) if(!version ||
(sscanf_s(version, "%d.%d", &major, &minor) != 2 &&
sscanf_s(version, "OpenGL ES %d.%d", &major, &minor) != 2))
{ {
DEBUG_WARN_ERR(ERR::LOGIC); // GL_VERSION invalid DEBUG_WARN_ERR(ERR::LOGIC); // GL_VERSION invalid
return false; return false;

View File

@ -15,6 +15,10 @@
# define BOOST_ALL_DYN_LINK # define BOOST_ALL_DYN_LINK
#endif #endif
// don't compile get_system_category() etc, since we don't use them and they
// sometimes cause problems when linking
#define BOOST_SYSTEM_NO_DEPRECATED
// the following boost libraries have been included in TR1 and are // the following boost libraries have been included in TR1 and are
// thus deemed usable: // thus deemed usable:
#define BOOST_FILESYSTEM_VERSION 2 #define BOOST_FILESYSTEM_VERSION 2

View File

@ -36,6 +36,7 @@ symbol lookups and backtraces)
#include "lib/timer.h" #include "lib/timer.h"
#include "lib/sysdep/sysdep.h" #include "lib/sysdep/sysdep.h"
#include "lib/debug.h" #include "lib/debug.h"
#include "lib/utf8.h"
Status debug_CaptureContext(void* UNUSED(context)) Status debug_CaptureContext(void* UNUSED(context))
@ -87,12 +88,29 @@ void udbg_launch_debugger()
} }
} }
#if OS_ANDROID
#include <android/log.h>
void debug_puts(const wchar_t* text)
{
// The Android logger doesn't like "%ls" format strings, so convert
// the message to UTF-8 before outputting
Status err;
std::string str = utf8_from_wstring(text, &err);
__android_log_print(ANDROID_LOG_WARN, "pyrogenesis", "%s", str.c_str());
}
#else
void debug_puts(const wchar_t* text) void debug_puts(const wchar_t* text)
{ {
printf("%ls", text); // must not use printf, since stdout is byte-oriented printf("%ls", text); // must not use printf, since stdout is byte-oriented
fflush(stdout); fflush(stdout);
} }
#endif
int debug_IsPointerBogus(const void* UNUSED(p)) int debug_IsPointerBogus(const void* UNUSED(p))
{ {
// TODO: maybe this should do some checks // TODO: maybe this should do some checks

View File

@ -38,8 +38,44 @@ struct WDIR
wdirent ent; wdirent ent;
}; };
#if OS_ANDROID
// The Crystax NDK seems to do weird things with opendir etc.
// To avoid that, load the symbols directly from the real libc
// and use them instead.
#include <dlfcn.h>
static void* libc;
static DIR* (*libc_opendir)(const char*);
static dirent* (*libc_readdir)(DIR*);
static int (*libc_closedir)(DIR*);
void init_libc()
{
if (libc)
return;
libc = dlopen("/system/lib/libc.so", RTLD_LAZY);
ENSURE(libc);
libc_opendir = (DIR*(*)(const char*))dlsym(libc, "opendir");
libc_readdir = (dirent*(*)(DIR*))dlsym(libc, "readdir");
libc_closedir = (int(*)(DIR*))dlsym(libc, "closedir");
ENSURE(libc_opendir && libc_readdir && libc_closedir);
}
#define opendir libc_opendir
#define readdir libc_readdir
#define closedir libc_closedir
#else
void init_libc() { }
#endif
WDIR* wopendir(const OsPath& path) WDIR* wopendir(const OsPath& path)
{ {
init_libc();
DIR* d = opendir(OsString(path).c_str()); DIR* d = opendir(OsString(path).c_str());
if(!d) if(!d)
return 0; return 0;

View File

@ -65,7 +65,7 @@ void sys_display_msg(const wchar_t* caption, const wchar_t* msg)
fprintf(stderr, "%ls: %ls\n", caption, msg); // must not use fwprintf, since stderr is byte-oriented fprintf(stderr, "%ls: %ls\n", caption, msg); // must not use fwprintf, since stderr is byte-oriented
} }
#if OS_MACOSX #if OS_MACOSX || OS_ANDROID
static ErrorReactionInternal try_gui_display_error(const wchar_t* text, bool manual_break, bool allow_suppress, bool no_continue) static ErrorReactionInternal try_gui_display_error(const wchar_t* text, bool manual_break, bool allow_suppress, bool no_continue)
{ {
// TODO: implement this, in a way that doesn't rely on X11 // TODO: implement this, in a way that doesn't rely on X11
@ -204,7 +204,7 @@ static ErrorReactionInternal try_gui_display_error(const wchar_t* text, bool man
ErrorReactionInternal sys_display_error(const wchar_t* text, size_t flags) ErrorReactionInternal sys_display_error(const wchar_t* text, size_t flags)
{ {
printf("%ls\n\n", text); debug_printf(L"%ls\n\n", text);
const bool manual_break = (flags & DE_MANUAL_BREAK ) != 0; const bool manual_break = (flags & DE_MANUAL_BREAK ) != 0;
const bool allow_suppress = (flags & DE_ALLOW_SUPPRESS) != 0; const bool allow_suppress = (flags & DE_ALLOW_SUPPRESS) != 0;
@ -215,6 +215,14 @@ ErrorReactionInternal sys_display_error(const wchar_t* text, size_t flags)
if (ret != ERI_NOT_IMPLEMENTED) if (ret != ERI_NOT_IMPLEMENTED)
return ret; return ret;
#if OS_ANDROID
// Android has no easy way to get user input here,
// so continue or exit automatically
if(no_continue)
abort();
else
return ERI_CONTINUE;
#else
// Otherwise fall back to the terminal-based input // Otherwise fall back to the terminal-based input
// Loop until valid input given: // Loop until valid input given:
@ -259,6 +267,7 @@ ErrorReactionInternal sys_display_error(const wchar_t* text, size_t flags)
return ERI_EXIT; // placebo; never reached return ERI_EXIT; // placebo; never reached
} }
} }
#endif
} }

View File

@ -535,7 +535,14 @@ static void RunGameOrAtlas(int argc, const char* argv[])
CXeromyces::Terminate(); CXeromyces::Terminate();
} }
int main(int argc, char* argv[]) #if OS_ANDROID
// In Android we compile the engine as a shared library, not an executable,
// so rename main() to a different symbol that the wrapper library can load
#undef main
#define main pyrogenesis_main
#endif
extern "C" int main(int argc, char* argv[])
{ {
#if OS_UNIX #if OS_UNIX
// Don't allow people to run the game with root permissions, // Don't allow people to run the game with root permissions,

View File

@ -170,11 +170,13 @@ void RunHardwareDetection()
scriptInterface.SetProperty(settings.get(), "os_unix", OS_UNIX); scriptInterface.SetProperty(settings.get(), "os_unix", OS_UNIX);
scriptInterface.SetProperty(settings.get(), "os_linux", OS_LINUX); scriptInterface.SetProperty(settings.get(), "os_linux", OS_LINUX);
scriptInterface.SetProperty(settings.get(), "os_android", OS_ANDROID);
scriptInterface.SetProperty(settings.get(), "os_macosx", OS_MACOSX); scriptInterface.SetProperty(settings.get(), "os_macosx", OS_MACOSX);
scriptInterface.SetProperty(settings.get(), "os_win", OS_WIN); scriptInterface.SetProperty(settings.get(), "os_win", OS_WIN);
scriptInterface.SetProperty(settings.get(), "arch_ia32", ARCH_IA32); scriptInterface.SetProperty(settings.get(), "arch_ia32", ARCH_IA32);
scriptInterface.SetProperty(settings.get(), "arch_amd64", ARCH_AMD64); scriptInterface.SetProperty(settings.get(), "arch_amd64", ARCH_AMD64);
scriptInterface.SetProperty(settings.get(), "arch_arm", ARCH_ARM);
#ifdef NDEBUG #ifdef NDEBUG
scriptInterface.SetProperty(settings.get(), "build_debug", 0); scriptInterface.SetProperty(settings.get(), "build_debug", 0);

View File

@ -24,6 +24,7 @@
#if OS_WIN #if OS_WIN
# include "lib/sysdep/os/win/wutil.h" // wutil_AppdataPath # include "lib/sysdep/os/win/wutil.h" // wutil_AppdataPath
#endif #endif
#include "ps/CLogger.h"
Paths::Paths(const CmdLineArgs& args) Paths::Paths(const CmdLineArgs& args)
@ -48,7 +49,13 @@ Paths::Paths(const CmdLineArgs& args)
} }
else else
{ {
#if OS_WIN #if OS_ANDROID
const OsPath appdata = OsPath("/sdcard/0ad/appdata");
m_data = appdata/"data"/"";
m_config = appdata/"config"/"";
m_cache = appdata/"cache"/"";
m_logs = appdata/"logs"/"";
#elif OS_WIN
const OsPath appdata = wutil_AppdataPath() / subdirectoryName/""; const OsPath appdata = wutil_AppdataPath() / subdirectoryName/"";
m_data = appdata/"data"/""; m_data = appdata/"data"/"";
m_config = appdata/"config"/""; m_config = appdata/"config"/"";
@ -72,6 +79,10 @@ Paths::Paths(const CmdLineArgs& args)
/*static*/ OsPath Paths::Root(const OsPath& argv0) /*static*/ OsPath Paths::Root(const OsPath& argv0)
{ {
#if OS_ANDROID
return OsPath("/sdcard/0ad"); // TODO: this is kind of bogus
#else
// get full path to executable // get full path to executable
OsPath pathname = sys_ExecutablePathname(); // safe, but requires OS-specific implementation OsPath pathname = sys_ExecutablePathname(); // safe, but requires OS-specific implementation
if(pathname.empty()) // failed, use argv[0] instead if(pathname.empty()) // failed, use argv[0] instead
@ -84,11 +95,16 @@ Paths::Paths(const CmdLineArgs& args)
// make sure it's valid // make sure it's valid
if(!FileExists(pathname)) if(!FileExists(pathname))
{
LOGERROR(L"Cannot find executable (expected at '%ls')", pathname.string().c_str());
WARN_IF_ERR(StatusFromErrno()); WARN_IF_ERR(StatusFromErrno());
}
for(size_t i = 0; i < 2; i++) // remove "system/name.exe" for(size_t i = 0; i < 2; i++) // remove "system/name.exe"
pathname = pathname.Parent(); pathname = pathname.Parent();
return pathname; return pathname;
#endif
} }

View File

@ -29,7 +29,9 @@
#include "lib/sysdep/snd.h" #include "lib/sysdep/snd.h"
#include "lib/sysdep/cpu.h" #include "lib/sysdep/cpu.h"
#include "lib/sysdep/os_cpu.h" #include "lib/sysdep/os_cpu.h"
#if ARCH_X86_X64
#include "lib/sysdep/arch/x86_x64/topology.h" #include "lib/sysdep/arch/x86_x64/topology.h"
#endif
#include "lib/sysdep/smbios.h" #include "lib/sysdep/smbios.h"
#include "lib/tex/tex.h" #include "lib/tex/tex.h"
@ -99,7 +101,10 @@ void WriteSystemInfo()
fprintf(f, "OS : %s %s (%s)\n", un.sysname, un.release, un.version); fprintf(f, "OS : %s %s (%s)\n", un.sysname, un.release, un.version);
// CPU // CPU
fprintf(f, "CPU : %s, %s (%dx%dx%d)", un.machine, cpu_IdentifierString(), (int)topology::NumPackages(), (int)topology::CoresPerPackage(), (int)topology::LogicalPerCore()); fprintf(f, "CPU : %s, %s", un.machine, cpu_IdentifierString());
#if ARCH_X86_X64
fprintf(f, " (%dx%dx%d)", (int)topology::NumPackages(), (int)topology::CoresPerPackage(), (int)topology::LogicalPerCore());
#endif
double cpuClock = os_cpu_ClockFrequency(); // query OS (may fail) double cpuClock = os_cpu_ClockFrequency(); // query OS (may fail)
#if ARCH_X86_X64 #if ARCH_X86_X64
if(cpuClock <= 0.0) if(cpuClock <= 0.0)

View File

@ -180,7 +180,7 @@ void ShaderModelRenderer::BeginPass(int streamflags)
} }
// Cleanup one rendering pass // Cleanup one rendering pass
void ShaderModelRenderer::EndPass(int streamflags) void ShaderModelRenderer::EndPass(int UNUSED(streamflags))
{ {
CVertexBuffer::Unbind(); CVertexBuffer::Unbind();
} }