The sluggish device is running now: https://www.youtube.com/watch?v=C8lzkl984Yc
To get the sluggish device feeling better I have added a full screen cache class.
class FullScreenCache
{
int width;
int height;
bool _is_init;
GlobalRef buffer;
jint* _dest;
Image _image;
public:
inline bool is_init()
{
return _is_init;
}
inline void update( int x_offset_, int y_offset_, Image& img )
{
Graphics g (_image);
g.drawImageAt(img,x_offset_,y_offset_);
}
inline Image& get_image()
{
return _image;
}
inline GlobalRef get_buffer()
{
return buffer;
}
inline bool init()
{
if( not _is_init )
{
width = Desktop::getInstance().getDisplays().getMainDisplay().userArea.getWidth();
height = Desktop::getInstance().getDisplays().getMainDisplay().userArea.getHeight();
buffer = GlobalRef( getEnv()->NewIntArray(width * height) );
_dest = getEnv()->GetIntArrayElements ((jintArray) buffer.get(), 0);
_image = Image( new PreallocatedImage (width, height, _dest, false) );
}
_is_init = true;
}
inline static FullScreenCache& instance()
{
static FullScreenCache this_;
return this_;
}
private:
FullScreenCache()
:
width( 0 ),
height( 0 ),
_image( Image::ARGB, 0,0, false ),
_is_init( false )
{}
Changed the handlePaintCallback to use the cache if it is just a touch down redraw request:
void handlePaintCallback (JNIEnv* env, jobject canvas, bool is_after_touch_ )
{
jobject rect = env->CallObjectMethod (canvas, CanvasMinimal.getClipBounds);
const int left = env->GetIntField (rect, RectClass.left);
const int top = env->GetIntField (rect, RectClass.top);
const int right = env->GetIntField (rect, RectClass.right);
const int bottom = env->GetIntField (rect, RectClass.bottom);
const int height = bottom - top;
const int width = right - left;
env->DeleteLocalRef (rect);
const Rectangle<int> clip (left, top, width, height);
// check if we need the cache hack
FullScreenCache& cache = FullScreenCache::instance();
if( use_cache_hack and is_fullscreen( width, height ) )
{
// make cache
if( not cache.is_init() or not is_after_touch_ )
{
cache.init();
LowLevelGraphicsSoftwareRenderer g (cache.get_image());
handlePaint (g);
}
// use cache
env->CallVoidMethod (canvas, CanvasMinimal.drawBitmap, (jintArray) cache.get_buffer().get(), 0, clip.getWidth(),
(jfloat) clip.getX(), (jfloat) clip.getY(),
clip.getWidth(), clip.getHeight(), false, (jobject) 0);
}
else
{
const int sizeNeeded = clip.getWidth() * clip.getHeight();
if (sizeAllocated < sizeNeeded)
{
buffer.clear();
sizeAllocated = sizeNeeded;
buffer = GlobalRef (env->NewIntArray (sizeNeeded));
}
if (jint* dest = env->GetIntArrayElements ((jintArray) buffer.get(), 0))
{
Image temp (new PreallocatedImage (clip.getWidth(), clip.getHeight(), dest, ! component.isOpaque()));
{
LowLevelGraphicsSoftwareRenderer g (temp);
g.setOrigin (-clip.getPosition());
handlePaint (g);
}
env->ReleaseIntArrayElements ((jintArray) buffer.get(), dest, 0);
env->CallVoidMethod (canvas, CanvasMinimal.drawBitmap, (jintArray) buffer.get(), 0, clip.getWidth(),
(jfloat) clip.getX(), (jfloat) clip.getY(),
clip.getWidth(), clip.getHeight(), true, (jobject) 0);
if( use_cache_hack and cache.is_init() )
cache.update(clip.getX(),clip.getY(),temp);
}
}
}
inline static bool is_fullscreen( int w_, int h_ )
{
static int w = Desktop::getInstance().getDisplays().getMainDisplay().userArea.getWidth();
static int h = Desktop::getInstance().getDisplays().getMainDisplay().userArea.getHeight();
if( w == w_ )
if( h == h_ )
return true;
return false;
}
JUCE_VIEW_CALLBACK (void, handlePaint, (JNIEnv* env, jobject view, jlong host, jobject canvas, jboolean is_after_touch), handlePaintCallback (env, canvas, is_after_touch))
At the Java side:
private native void handlePaint (long host, Canvas canvas, boolean is_after_touch );
private boolean is_after_touch = false;
@Override
public void onDraw (Canvas canvas)
{
handlePaint (host, canvas, is_after_touch);
is_after_touch = false;
}
@Override
public boolean onTouchEvent (MotionEvent event)
{
...
case MotionEvent.ACTION_DOWN:
is_after_touch = true;
//Debug.startMethodTracing("handleMouseDown");
handleMouseDown (host, event.getPointerId(0), event.getX(), event.getY(), event.getEventTime());
return true;
...
}
This is ~300ms faster than before.
NOTE: this on touch full redraw is only on the arm device. The x86 device does not request a full redraw on touch. I don't know what's going wrong! I have also opend a thread on stackoverflow: http://stackoverflow.com/questions/25832648/why-does-android-requests-a-full-redraw-after-a-touch-event-but-only-on-a-arm-d
Sorry for that bad thread quality - it was driving me crazy!
EDIT: change code: memory for cache will only allocated if a device have the onTouch full redraw "problem"