Recent

Author Topic: FPC4Android branch  (Read 84359 times)

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3538
Re: FPC4Android branch
« Reply #15 on: March 30, 2012, 10:29:10 am »
There are various ways to have faster pixel access then TCanvas.Pixels:

1->Use TLazIntfImage, read this entire section:

http://wiki.lazarus.freepascal.org/Developing_with_Graphics#Working_with_TLazIntfImage.2C_TRawImage_and_TLazCanvas

You need to allocate a TLazIntfImage (by loading it from a TBitmap or by creating a TRawImage for it), draw to it, then convert it to a TBitmap and draw this to the Canvas

2->If you are using LCL-CustomDrawn you can access the TLazCanvas object which are inside TCanvas in this widgetset:

http://wiki.lazarus.freepascal.org/Custom_Drawn_Interface#Getting_the_TLazCanvas_object_inside_TCanvas

TLazCanvas.Image holds the associated TLazIntfImage, but I think that this property became public only in FPC 2.6.1

TCanvas.Pixels in LCL-CustomDrawn just calls TLazCanvas.Colors

TLazCanvas.Colors executes object clipping, windoworg and other important settings and calls TLazIntfImage.Colors to do the real work

TLazIntfImage.Colors makes no clipping, no position adjustment, only converts TFPColor to the internal format, so it is the fastest

Each TWinControl has it's own TLazCanvas in LCL-CustomDrawn in recent revisions, in the past there was only 1 for the entire form.

meanderix

  • Jr. Member
  • **
  • Posts: 50
Re: FPC4Android branch
« Reply #16 on: March 30, 2012, 11:55:29 am »
Thanks Felipe. I will definitely read up on this. I'm using FPC 2.6.1, but I'm using the units that you provided in the original post (so I guess it's 2.5.1.) I guess for 2.6.1 I need to crosscompile them on my own?

Btw, I'm planning to update my VPR polygon rasterizer so that it will work on LCL and Android:

http://vpr.sourceforge.net

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3538
Re: FPC4Android branch
« Reply #17 on: March 30, 2012, 12:02:54 pm »
I guess for 2.6.1 I need to crosscompile them on my own?

The standard FPC does not support Android, so I have my own branches. Read here:

http://wiki.lazarus.freepascal.org/Custom_Drawn_Interface/Android#Free_Pascal_Bugs_on_Android_Support

But it is some work to fix 2.6.1, so for now I am not working on this, but patches for my branch to fix support for Android in FPC4Android 2.6.1 are welcome. The wiki has a list of bugs to revert and patches to apply. Applying patches is easy, but there is no simple patch to fully revert the bugs at the moment. If someone makes one, I'll apply it.

meanderix

  • Jr. Member
  • **
  • Posts: 50
Re: FPC4Android branch
« Reply #18 on: April 02, 2012, 04:02:16 pm »
Hi Felipe,

I have one of the Graphics32 projects running on Android now (I created a new backend class that uses TRawImage and RawImage_CreateBitmaps to create a temporary bitmap that is painted onto the canvas.)

However, I noticed that Application.OnIdle is never triggered, so I need to rely on timers to invalidate the PaintBox.

Also, I get a lot of the following messages in the debugger:

D/dalvikvm(32473): GC_EXTERNAL_ALLOC freed 15K, 53% free 2578K/5379K, external 1535K/1911K, paused 15ms
D/dalvikvm(32473): GC_EXTERNAL_ALLOC freed 15K, 53% free 2578K/5379K, external 1535K/1911K, paused 15ms
D/dalvikvm(32473): GC_EXTERNAL_ALLOC freed 15K, 53% free 2578K/5379K, external 1535K/1911K, paused 15ms
D/dalvikvm(32473): GC_EXTERNAL_ALLOC freed 15K, 53% free 2578K/5379K, external 1535K/1911K, paused 15ms
D/dalvikvm(32473): GC_EXTERNAL_ALLOC freed 15K, 53% free 2578K/5379K, external 1535K/1911K, paused 15ms
D/dalvikvm(32473): GC_EXTERNAL_ALLOC freed 15K, 53% free 2578K/5379K, external 1535K/1911K, paused 15ms
D/dalvikvm(32473): GC_EXTERNAL_ALLOC freed 15K, 53% free 2578K/5379K, external 1535K/1911K, paused 15ms
D/dalvikvm(32473): GC_EXTERNAL_ALLOC freed 15K, 53% free 2578K/5379K, external 1535K/1911K, paused 15ms

The FPS is very low compared to if you run it in Windows and I'm wondering if all these pauses are making things slower?

Mattias

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3538
Re: FPC4Android branch
« Reply #19 on: April 02, 2012, 05:48:36 pm »
The FPS is very low compared to if you run it in Windows and I'm wondering if all these pauses are making things slower?

Why do you think that those are pauses? Those are garbage collector messages, they seam to be generated on every repaint and nothing indicates that they are a problem, although it could be.

Originally I thought they were related to the fact that I didn't free strings generated via NewStringUTF, and you don't really need to free them, the garbage collector takes care of that. Now I added explicit code to free them and I couldn't note any difference, so I have no idea anymore.

It is very hard to say what makes things slower then they could be because I already did a lot of optimizing now. We really need to start doing profiling of various parts and see where optimizations can be achieved.

meanderix

  • Jr. Member
  • **
  • Posts: 50
Re: FPC4Android branch
« Reply #20 on: April 02, 2012, 08:20:16 pm »
The FPS is very low compared to if you run it in Windows and I'm wondering if all these pauses are making things slower?

Why do you think that those are pauses? Those are garbage collector messages, they seam to be generated on every repaint and nothing indicates that they are a problem, although it could be.

Hmm, ok, I'm completely new to Android development, so I'm basically trying to interpret what I'm seeing in the debugger. Maybe this is not the bottleneck at all.

Quote
Originally I thought they were related to the fact that I didn't free strings generated via NewStringUTF, and you don't really need to free them, the garbage collector takes care of that. Now I added explicit code to free them and I couldn't note any difference, so I have no idea anymore.

It is very hard to say what makes things slower then they could be because I already did a lot of optimizing now. We really need to start doing profiling of various parts and see where optimizations can be achieved.

I checked in a new backend class to the Graphics32 repository today for the CustomDrawn widget set. It's probably not 100% bug free at the moment and I've not tested the ICanvasSupport and IDeviceContextSupport implementations.

I managed to get the GradLines_Ex example project running on my SGS2, but I had to remove the memo control, otherwise it would crash on startup.

I don't know how you would go about profiling an Android application, but I guess there must be some tools for this?
« Last Edit: April 02, 2012, 08:23:45 pm by meanderix »

meanderix

  • Jr. Member
  • **
  • Posts: 50
Re: FPC4Android branch
« Reply #21 on: April 04, 2012, 02:34:40 pm »
Ok, I've optimized the repaint process a bit (I'm accessing TLazCanvas using Canvas.Handle.) It's faster now, but it seems the bottleneck is really the timer. It seems the timer is triggered only about every 200ms, even if I have an interval of 1ms. It would be great if I could use Application.OnIdle -- but that does not seem to be triggered at the moment. I'll take a look at other possibilities.
« Last Edit: April 04, 2012, 02:52:27 pm by meanderix »

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3538
Re: FPC4Android branch
« Reply #22 on: April 04, 2012, 03:14:48 pm »
Ok, I've optimized the repaint process a bit (I'm accessing TLazCanvas using Canvas.Handle.) It's faster now, but it seems the bottleneck is really the timer. It seems the timer is triggered only about every 200ms, even if I have an interval of 1ms.

The timer is native, so I am not sure if we can do anything about this. Try googling about Runnable in Android or asking in an android google group.

See the file lazarus/examples/androidlcl/android/src/com/pascal/lcltest/LCLActivity.java

Code: [Select]
 
  // input:  int lcltimerinterval in milliseconds
  // output:  Runnable lcltimerid
  public void LCLDoCreateTimer()
  {
    lcltimerid = new LCLRunnable();

    LocalHandler.removeCallbacks(lcltimerid);
    LocalHandler.postDelayed(lcltimerid, lcltimerinterval);
  };

Quote
It would be great if I could use Application.OnIdle -- but that does not seem to be triggered at the moment. I'll take a look at other possibilities.

I am not sure if OnIndle can be implemented in Android at all. Maybe if there is a native event for that. We have zero control over the application loop in Android, we only receive events from the system, so either it has an idle event or not.

Googling for "android event onidle" without quotes brings people asking on the topic but no real answer.

You could try asking in one of the Google Android Groups and post back to me if anyone has a positive answer.

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3538
Re: FPC4Android branch
« Reply #23 on: April 04, 2012, 03:24:19 pm »
Quote
I managed to get the GradLines_Ex example project running on my SGS2, but I had to remove the memo control, otherwise it would crash on startup.

Yes, TMemo is not yet implemented, but it is a top thing in my ToDo

Quote
I don't know how you would go about profiling an Android application, but I guess there must be some tools for this?

I use this very simple method:

http://wiki.lazarus.freepascal.org/Profiling#Simple_profiling_using_ifdefs_and_timing_routines

In lazarus/lcl/interfaces/customdrawn/customdrawndefines.inc there is:

{.$define VerboseCDPaintProfiler}

You can activate it to profile the internal painting, but this profiles the LCL, not your code. In your code you need to write such code.

meanderix

  • Jr. Member
  • **
  • Posts: 50
Re: FPC4Android branch
« Reply #24 on: April 06, 2012, 12:02:15 am »
Hi again Felipe and thanks for the info.

I'm now observing the following: the FPS will increase if I hide controls on the form (even if I don't actually do any repaints in the OnTimer event.) Also, when the app is running in the background, the FPS increases by a factor 10-200, depending on how many controls are visible and depending on if I'm doing any processing in OnTimer.

Will the OnTimer event cause the form and its child controls to be invalidated? (I would have expected that this event would be independent of the paint events.)

My OnTimer event:
Code: [Select]
var
  FrameCount, TC1, TC2: Cardinal;

procedure TFormGradientLines.Timer1Timer(Sender: TObject);
begin
  if FrameCount >= 10 then
  begin
    TC2 := GetTickCount;
    DebugLn(Format('FPS: %.3f', [1000000*FrameCount / (TC2 - TC1)]));
    FrameCount := 0;
    TC1 := GetTickCount;
  end;
  Inc(FrameCount);
end;     

BTW: it seems GetTickCount returns the time in microseconds and not in milliseconds.
« Last Edit: April 06, 2012, 01:35:02 am by meanderix »

meanderix

  • Jr. Member
  • **
  • Posts: 50
Re: FPC4Android branch
« Reply #25 on: April 06, 2012, 01:22:09 am »
LCLRunnable uses the following run method:
Code: [Select]
    public void run()
    {
      int eventResult = LCLOnTimer(this);
      ProcessEventResult(eventResult);
      if (this.Destroyed == false) LocalHandler.postDelayed(this, lcltimerinterval);
    }

ProcessEventResult is implemented like this:
Code: [Select]
  public void ProcessEventResult(int eventResult)
  {
    if (((eventResult | 1) != 0) && (lclsurface != null)) lclsurface.postInvalidate();
    //if ((eventResult | 2) != 0) reserved for BACK key handling
  }

And then LCLDoCreateTimer is implemented like this:
Code: [Select]
  public void LCLDoCreateTimer()
  {
    lcltimerid = new LCLRunnable();

    LocalHandler.removeCallbacks(lcltimerid);
    LocalHandler.postDelayed(lcltimerid, lcltimerinterval);
  };

So it seems the timer does indeed invoke lclsurface.postInvalidate().

But would it be possible to change this behavior somehow?
« Last Edit: April 06, 2012, 01:32:46 am by meanderix »

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3538
Re: FPC4Android branch
« Reply #26 on: April 06, 2012, 06:54:35 am »
You are making a wrong reading of the code.

The eventResult is the way which we use to pass information from Pascal callbacks into the Java side (although not the only one), and the first bit if set indicates that the Pascal side has executed a call to Invalidate. So the check:

    if (((eventResult | 1) != 0) && (lclsurface != null)) lclsurface.postInvalidate();

will only be true if something in the Pascal side explicitly calls Invalidate. Many things do this, for example: A blinking caret (but it has it's own timer), a button being pressed (but then the event is touch down/up not timer), etc. In your own timer it should only return in true if you call Invalidate in the timer callback. You failed to follow the code here:

      int eventResult = LCLOnTimer(this);

LCLOnTimer is implemented in the LCL in lazarus/lcl/interfaces/customdrawn/customdrawnobject_android.inc

You should have added log information to check if the invalidation is being done when not asked, although I doubt it. Simply removing the invalidation is a completely wrong solution to anything, it would break at least caret blinking, and potentially the entire UI.
« Last Edit: April 06, 2012, 06:57:09 am by felipemdc »

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3538
Re: FPC4Android branch
« Reply #27 on: April 06, 2012, 07:25:44 am »
Ops, rethinking now I think I used the wrong operator =) I think it should have been:

    if (((eventResult & 1) != 0) && (lclsurface != null)) lclsurface.postInvalidate();

Could you try that line like that?

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3538
Re: FPC4Android branch
« Reply #28 on: April 06, 2012, 09:43:51 am »
I commited this change, please test with rev >= 36586

meanderix

  • Jr. Member
  • **
  • Posts: 50
Re: FPC4Android branch
« Reply #29 on: April 06, 2012, 11:07:31 am »
Ops, rethinking now I think I used the wrong operator =) I think it should have been:

    if (((eventResult & 1) != 0) && (lclsurface != null)) lclsurface.postInvalidate();

Could you try that line like that?
Ok, seems this fixed the problem. I'm still trying to figure out if it's possible to speed up the invalidation as well.

 

TinyPortal © 2005-2018