[PATCH] Android: glretracer for Android.
Alexander Monakov
amonakov at ispras.ru
Thu Jun 27 10:29:46 PDT 2013
Hello,
Thanks for sharing this. We have implemented an Android retracer using a
different approach: we have a minimal Java app that invokes native retrace
code via JNI and provides it with drawable surfaces. It's not ideal, but at
least it avoids the need to worry about window creation issues. Overall your
approach with Waffle is very elegant.
Some comments on the patch inline.
On Thu, 27 Jun 2013, Juha-Pekka Heikkila wrote:
> diff --git a/CMakeLists.txt b/CMakeLists.txt
> index d819be2..1642b01 100644
> --- a/CMakeLists.txt
> +++ b/CMakeLists.txt
> @@ -1,5 +1,6 @@
> cmake_minimum_required (VERSION 2.8)
>
> +include(CheckIncludeFiles)
Looks unused.
>
> # Use clang on MacOSX. gcc doesn't support __thread key, and Apple has
> # abandoned it for clang. This must be done before the project is defined.
> @@ -61,7 +62,18 @@ else ()
> endif ()
>
> find_host_package (PythonInterp REQUIRED)
> -find_package (Threads)
> +if (NOT ANDROID)
> + find_package (Threads)
> +endif ()
I don't see why you need this change.
> +
> +if (ANDROID)
> +#########
> +# In following the name waffle-1 should be fixed to found out properly.
> + find_path (Waffle_INCLUDE_DIRS NAMES waffle.h PATHS "$ENV{OUT}/obj/include/waffle-1" "$ENV{OUT}/obj/lib" "$ENV{ANDROID_BUILD_TOP}/external/waffle" NO_CMAKE_FIND_ROOT_PATH )
> +
> + find_library (Waffle NAMES "waffle-1" PATHS "$ENV{OUT}/obj/include/waffle-1" "$ENV{OUT}/obj/lib" "$ENV{ANDROID_BUILD_TOP}/external/waffle" REQUIRED NO_CMAKE_FIND_ROOT_PATH NO_DEFAULT_PATH)
> + include_directories (${Waffle_INCLUDE_DIRS})
> +endif ()
>
> if (ENABLE_GUI)
> if (NOT (ENABLE_GUI STREQUAL "AUTO"))
> @@ -294,6 +306,12 @@ include_directories (
> ${CMAKE_CURRENT_SOURCE_DIR}/common
> )
>
> +#if (ANDROID)
> +# include_directories ( BEFORE
> +# $ENV{ANDROID_BUILD_TOP}/external/ltp/tools/top-LTP
> +# )
> +#endif ()
> +
> if (WIN32)
> set (os os_win32.cpp)
> set (glws_os glws_wgl.cpp)
> @@ -302,7 +320,11 @@ else ()
> if (APPLE)
> set (glws_os glws_cocoa.mm)
> else ()
> - set (glws_os glws_glx.cpp)
> + if (ANDROID)
> + set (glws_os glws_waffle.cpp)
> + else ()
> + set (glws_os glws_glx.cpp)
> + endif ()
> endif ()
> endif ()
>
> diff --git a/dispatch/glproc_gl.cpp b/dispatch/glproc_gl.cpp
> index 2516dab..f793d1c 100644
> --- a/dispatch/glproc_gl.cpp
> +++ b/dispatch/glproc_gl.cpp
> @@ -26,6 +26,9 @@
>
> #include "glproc.hpp"
>
> +#if defined(__ANDROID__)
> +#include <waffle.h>
> +#endif
I don't see why you're modifying glproc_gl.cpp; only glproc_egl should come
into play on Android.
>
> #if !defined(_WIN32)
> #include <unistd.h> // for symlink
> @@ -272,7 +275,12 @@ _getPublicProcAddress(const char *procName)
> void *
> _getPrivateProcAddress(const char *procName)
> {
> +#ifdef __ANDROID__
> + extern int waffle_gl_api;
> + return waffle_dl_sym(waffle_gl_api, procName);
> +#else
> return (void *)_glXGetProcAddressARB((const GLubyte *)procName);
> +#endif
> }
>
>
> diff --git a/retrace/CMakeLists.txt b/retrace/CMakeLists.txt
> index 78cceae..c2de4fc 100644
> --- a/retrace/CMakeLists.txt
> +++ b/retrace/CMakeLists.txt
> @@ -9,6 +9,12 @@ include_directories (
> ${CMAKE_SOURCE_DIR}/image
> )
>
> +if (ANDROID)
> + include_directories ( BEFORE
> + $ENV{ANDROID_BUILD_TOP}/external/ltp/tools/top-LTP
> + )
> +endif ()
> +
Unrelated change?
> add_definitions (-DRETRACE)
>
> add_custom_command (
> @@ -40,13 +46,55 @@ add_library (retrace_common STATIC
> retrace_swizzle.cpp
> json.cpp
> )
> -target_link_libraries (retrace_common
> - image
> - common
> - ${ZLIB_LIBRARIES}
> - ${SNAPPY_LIBRARIES}
> - ${GETOPT_LIBRARIES}
> -)
> +
> +if (ANDROID)
> +
> +#########
> +# In following the name waffle-1 should be fixed to found out properly.
> + find_path (Waffle_INCLUDE_DIRS
> + NAMES waffle.h
> + PATHS "$ENV{OUT}/obj/include/waffle-1"
> + "$ENV{OUT}/obj/lib" "$ENV{ANDROID_BUILD_TOP}/external/waffle"
> + NO_CMAKE_FIND_ROOT_PATH
> + )
> +
> + find_library (Waffle
> + NAMES "waffle-1"
> + PATHS "$ENV{OUT}/obj/include/waffle-1" "$ENV{OUT}/obj/lib"
> + "$ENV{ANDROID_BUILD_TOP}/external/waffle"
> + REQUIRED NO_CMAKE_FIND_ROOT_PATH NO_DEFAULT_PATH
> + )
> +
> + include_directories (${Waffle_INCLUDE_DIRS})
> +
> + if (POLICY CMP0016)
> + cmake_policy (PUSH)
> + cmake_policy (SET CMP0016 OLD)
> + endif ()
Why do you need to suppress this cmake warning?
> +
> + target_link_libraries (retrace_common
> + image
> + common
> + ${ZLIB_LIBRARIES}
> + ${SNAPPY_LIBRARIES}
> + ${GETOPT_LIBRARIES}
> + ${Waffle}
> + )
> +
> + if (POLICY CMP0016)
> + cmake_policy (POP)
> + endif ()
> +
> +
> +else ()
> + target_link_libraries (retrace_common
> + image
> + common
> + ${ZLIB_LIBRARIES}
> + ${SNAPPY_LIBRARIES}
> + ${GETOPT_LIBRARIES}
> + )
> +endif ()
>
> add_library (glretrace_common STATIC
> glretrace_gl.cpp
> @@ -68,7 +116,7 @@ target_link_libraries (glretrace_common
> )
>
>
> -if (WIN32 OR APPLE OR X11_FOUND)
> +if (WIN32 OR APPLE OR X11_FOUND OR ANDROID)
> add_executable (glretrace
Hm. Do you need both glretrace and eglretrace on Android?
> ${glws_os}
> )
> @@ -90,19 +138,31 @@ if (WIN32 OR APPLE OR X11_FOUND)
> #"-framework OpenGL" # CGL*
> )
> else ()
> - target_link_libraries (glretrace ${X11_X11_LIB})
> + if (NOT ANDROID)
> + target_link_libraries (glretrace ${X11_X11_LIB})
> + endif()
> endif ()
>
> - target_link_libraries (glretrace
> - # gdb doesn't like when pthreads is loaded through dlopen (which happens
> - # when dlopen'ing libGL), so link pthreads to avoid this issue. See also
> - # http://stackoverflow.com/questions/2702628/gdb-cannot-find-new-threads-generic-error
> - ${CMAKE_THREAD_LIBS_INIT}
> - dl
> - )
> +
> + if (ANDROID)
> + target_link_libraries (glretrace
> + dl
> + )
> + else()
> + target_link_libraries (glretrace
> + # gdb doesn't like when pthreads is loaded through dlopen (which happens
> + # when dlopen'ing libGL), so link pthreads to avoid this issue. See also
> + # http://stackoverflow.com/questions/2702628/gdb-cannot-find-new-threads-generic-error
> + ${CMAKE_THREAD_LIBS_INIT}
> + dl
> + )
> + endif ()
>
> if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
> - target_link_libraries (glretrace rt)
> + if (NOT ANDROID)
> + target_link_libraries (glretrace rt)
> + endif ()
> +
> if (READPROC_H_FOUND)
> target_link_libraries (glretrace ${proc_LIBRARY})
> endif ()
> @@ -120,14 +180,24 @@ if (ENABLE_EGL AND X11_FOUND AND NOT WIN32 AND NOT APPLE)
>
> add_dependencies (eglretrace glproc)
>
> - target_link_libraries (eglretrace
> - retrace_common
> - glretrace_common
> - glproc_egl
> - ${X11_X11_LIB}
> - ${CMAKE_THREAD_LIBS_INIT}
> - dl
> - )
> + if (ANDROID)
> + target_link_libraries (eglretrace
> + retrace_common
> + glretrace_common
> + glproc_egl
> + cutils
> + dl
> + )
> + else ()
> + target_link_libraries (eglretrace
> + retrace_common
> + glretrace_common
> + glproc_egl
> + ${X11_X11_LIB}
> + ${CMAKE_THREAD_LIBS_INIT}
> + dl
> + )
> + endif ()
>
> if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
> target_link_libraries (eglretrace rt)
> diff --git a/retrace/glws_waffle.cpp b/retrace/glws_waffle.cpp
> new file mode 100644
> index 0000000..d77cff0
> --- /dev/null
> +++ b/retrace/glws_waffle.cpp
> @@ -0,0 +1,227 @@
> +#include "waffle.h"
> +#include "glws.hpp"
> +
> +extern "C" {
> +int waffle_gl_api = 0;
> +};
> +
> +namespace glws {
> +
> +struct waffle_display *dpy;
> +
> +class WaffleVisual : public Visual
> +{
> +public:
> + struct waffle_config *config;
> +
> + WaffleVisual()
> + {
> + this->config = NULL;
createVisual code should probably go here.
> + }
> +
> + ~WaffleVisual() {
> + waffle_config_destroy(this->config);
Watch indentation.
> + }
> +};
> +
> +class WaffleDrawable : public Drawable
> +{
> +public:
> +
> + struct waffle_window *window;
> +
> + WaffleDrawable(const Visual *vis, int w, int h, bool pbuffer) :
> + Drawable(vis, w, h, pbuffer)
> + {
> + const WaffleVisual *waffleVisual =
> + static_cast<const WaffleVisual *>(vis);
> +
> + window = waffle_window_create(waffleVisual->config, w, h);
> + }
> +
> + void
> + resize(int w, int h) {
> + if (w == width && h == height) {
> + return;
> + }
> +
> + waffle_window_resize(window, w, h);
> + Drawable::resize(w, h);
> + }
> +
> + void show(void) {
> + if (visible) {
> + return;
> + }
> +
> + waffle_window_show(window);
> + Drawable::show();
> + }
> +
> + void swapBuffers(void) {
> + waffle_window_swap_buffers(window);
> + }
> +};
> +
> +class WaffleContext : public Context
> +{
> +public:
> + struct waffle_context *context;
> +
> + WaffleContext(const Visual *vis, Profile prof,
> + struct waffle_context *ctx) :
> + Context(vis, prof),
> + context(ctx)
> + {}
> +
> + ~WaffleContext() {
> + }
> +};
> +
> +/*
> + * With waffle there is not too many events to look for..
> + */
> +bool
> +processEvents(void) {
> + return true;
> +}
> +
> +void
> +init(void) {
> + int i;
> + int waffle_init_attrib_list[3];
> +
> + i = 0;
> + waffle_init_attrib_list[i++] = WAFFLE_PLATFORM;
> + waffle_init_attrib_list[i++] = WAFFLE_PLATFORM_ANDROID;
> + waffle_init_attrib_list[i++] = WAFFLE_NONE;
> +
> + waffle_init(waffle_init_attrib_list);
> +
> + dpy = waffle_display_connect(NULL);
> + if (!dpy)
> + {
> + printf("no display!!\n");
Can you use os::log instead?
> + }
> +}
> +
> +void
> +cleanup(void) {
> + waffle_display_disconnect(dpy);
> +}
> +
> +Visual *
> +createVisual(bool doubleBuffer, Profile profile) {
> + WaffleVisual *visual = new WaffleVisual();
> +
> + int config_attrib_list[64], i;
> +
> + i = 0;
> + config_attrib_list[i++] = WAFFLE_CONTEXT_API;
> +
> + switch (profile) {
> + case PROFILE_COMPAT:
> + if(!waffle_display_supports_context_api(dpy, WAFFLE_DL_OPENGL))
> + return NULL;
> + waffle_gl_api = config_attrib_list[i++] = WAFFLE_DL_OPENGL;
> + break;
> + case PROFILE_CORE:
> + assert(0);
> + return NULL;
> + case PROFILE_ES1:
> + if(!waffle_display_supports_context_api(dpy,
> + WAFFLE_CONTEXT_OPENGL_ES1))
> + return NULL;
> +
> + config_attrib_list[i++] = WAFFLE_CONTEXT_OPENGL_ES1;
> + waffle_gl_api = WAFFLE_DL_OPENGL_ES1;
> + break;
> + case PROFILE_ES2:
> + if(!waffle_display_supports_context_api(dpy,
> + WAFFLE_CONTEXT_OPENGL_ES2))
> + return NULL;
> +
> + config_attrib_list[i++] = WAFFLE_CONTEXT_OPENGL_ES2;
> + waffle_gl_api = WAFFLE_DL_OPENGL_ES2;
> + break;
> + default:
> + return NULL;
> + }
> +
> + config_attrib_list[i++] = WAFFLE_RED_SIZE;
> + config_attrib_list[i++] = 8;
> + config_attrib_list[i++] = WAFFLE_GREEN_SIZE;
> + config_attrib_list[i++] = 8;
> + config_attrib_list[i++] = WAFFLE_BLUE_SIZE;
> + config_attrib_list[i++] = 8;
> + config_attrib_list[i++] = WAFFLE_DEPTH_SIZE;
> + config_attrib_list[i++] = 8;
> + config_attrib_list[i++] = WAFFLE_ALPHA_SIZE;
> + config_attrib_list[i++] = 8;
> + config_attrib_list[i++] = WAFFLE_STENCIL_SIZE;
> + config_attrib_list[i++] = 8;
> + config_attrib_list[i++] = WAFFLE_DOUBLE_BUFFERED;
> + config_attrib_list[i++] = true;
> + config_attrib_list[i++] = 0;
> +
> + visual->config = waffle_config_choose(dpy, config_attrib_list);
> + if (!visual->config)
> + {
> + printf("Error in %s waffle_config_choose(dpy, config_attrib_list)\n",
> + __FILE__);
> + return NULL;
> + }
> +
> + return visual;
> +}
> +
> +Drawable *
> +createDrawable(const Visual *visual, int width, int height, bool pbuffer)
> +{
> + return new WaffleDrawable(visual, width, height, pbuffer);
> +}
> +
> +Context *
> +createContext(const Visual *visual, Context *shareContext, Profile profile,
> + bool debug)
> +{
> + struct waffle_context *ctx;
> + const WaffleVisual *waffleVisual =
> + static_cast<const WaffleVisual *>(visual);
> +
> + ctx = waffle_context_create(waffleVisual->config, NULL);
> + if (!ctx)
> + {
> + printf("Error in %s waffle_context_create(config, NULL)\n",
> + __FILE__);
> + return NULL;
> + }
> + return new WaffleContext(visual, profile, ctx );
> +}
> +
> +bool
> +makeCurrent(Drawable *drawable, Context *context)
> +{
> +
> + if (!drawable || !context) {
> + /*
> + * hm.
> + * Following cause inside waffle
> + * eglMakeCurrent(dpy, NULL, NULL, NULL) which equal to
> + * eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, \
> + * EGL_NO_CONTEXT)
> + * Lets hope things stay that way...
> + */
I think this comment can be safely removed :)
> + return waffle_make_current(dpy, NULL, NULL);
> + }
> + else {
> + WaffleDrawable *waffleDrawable =
> + static_cast<WaffleDrawable *>(drawable);
> + WaffleContext *waffleContext =
> + static_cast<WaffleContext *>(context);
> + return waffle_make_current(dpy, waffleDrawable->window,
> + waffleContext->context);
> + }
> +}
> +
> +} /* namespace glws */
>
More information about the apitrace
mailing list