Lazarus Cross-platform Fullscreen Support

I’m currently working on fast bitmap techniques for Lazarus, for which I will be posting a separate article in the future. However, whilst working on this I have encountered an old bug-bear of mine, implementing full-screen support. If your not familiar with the concept, most browsers now support this mode of operation, where they can take over use of the whole screen, removing all traces of the operating system from the display. This is also common in computer games and video players. It is very likely that the browser you are reading this in supports this feature. On PCs pressing F11 should swap into and out of fullscreen mode.

In Lazarus’ LCL library there is now an additional WindowState property for forms of wsFullScreen. This aims to simplify the process of taking over control of the whole display in a cross-platform manner for all LCL based applications. A naive use of this technique within a Lazarus application would look like this:

Unit Main;

{$mode objfpc}{$H+}

Interface

Uses
  Classes, SysUtils, FileUtil, Forms,
  Controls, Graphics, Dialogs, StdCtrls;

Type
  TMainForm = Class(TForm)
    FullscreenButton: TButton;
    RestoreButton: TButton;
    Procedure FullscreenButtonClick(Sender: TObject);
    Procedure RestoreButtonClick(Sender: TObject);
  End;

Var
  MainForm: TMainForm;

Implementation

{$R *.lfm}

Procedure TMainForm.FullscreenButtonClick(Sender: TObject);
Begin
  WindowState := wsFullScreen;
End;

Procedure TMainForm.RestoreButtonClick(Sender: TObject);
Begin
  WindowState := wsNormal;
End;

End.


This works perfectly on Linux(QT), but on Windows the form border is not hidden in fullscreen mode and worse still Linux(GTK2) completely fails to restore the window. No doubt these are teething problems that will be resolved in due course, but it is frustrating if you want to create a reliable cross-platform solution using the LCL framework. Fortunately, there are a couple of simple tweaks that can be applied to this code to make it work reliably across the main Lazarus target platforms.

Firstly, the GTK2 failure to restore seems to be due to the WindowState change not actually being applied. The trick here is to change the state to maximized immediately before the change to normal. This persuades GTK2 to do the right thing without adversely effecting the other platforms. So the restore procedure now looks like this:


Procedure TMainForm.RestoreButtonClick(Sender: TObject);
Begin
  WindowState := wsMaximized;
  WindowState := wsNormal;
End;

To deal with the failure to remove the border on Windows, we have to do that explicitly using the BorderStyle property. This leads to the procedures looking like this:


Procedure TMainForm.FullscreenButtonClick(Sender: TObject);
Begin
  BorderStyle := bsNone;
  WindowState := wsFullScreen;
End;

Procedure TMainForm.RestoreButtonClick(Sender: TObject);
Begin
  WindowState := wsMaximized;
  WindowState := wsNormal;
  BorderStyle := bsSizeable;
End;

Unfortunately, changing the border style interferes with the position of the restored window. So to tidy this up, the BoundsRect of the window needs to be recorded prior to changing to fullscreen, then set again upon restoration. I like to wrap this behaviour in an auto-checking Action so that it can be associated with a keyboard short cut (F11). Thus, the final routine I use in production code looks like this:


Var
  WindowRect: TRect;

Procedure TMainForm.FullscreenActionExecute(Sender: TObject);
Begin
  Begin
    If FullscreenAction.Checked Then
      Begin
        WindowRect := BoundsRect;
        BorderStyle := bsNone;
        WindowState := wsFullScreen;
      End
    Else
      Begin
        BorderStyle := bsSizeable;
        WindowState := wsMaximized;
        WindowState := wsNormal;
        BoundsRect := WindowRect;
      End;
  End;
End; 

Counting Intel CPU Clock Ticks

Accurately timing sections of a program for performance profiling is a surprisingly error prone task.  Whilst timer circuitry exists on all modern PC motherboards, it is designed for long duration use and can only perform accurate timing in the millisecond range or longer.  Modern CPUs execute at gigahertz frequencies and therefore need timing capabilities in the nanosecond range to be useful for code profiling.

The obvious solution is to read the CPU’s own internal clock tick counter as this is the actual mechanism used by the chip itself.  Fortunately, Intel have exposed this tick count through the rdtsc instruction, which returns the CPU tick count since the chip was powered up.  It is tempting to imagine that dividing this number by the processor’s clock frequency will yield a nanosecond precise time value.  This used to be true for older generations of Intel CPU’s running single process operating systems, but this is no longer the case.

Firstly, there is a conflict of interest between power use and performance.  Chips consume energy for every clock cycle completed, so chip makers have developed sophisticated methods of adjusting the actual clock speed depending upon current system load.  As a result, it is not possible to be certain of the clock frequency in effect at any given moment, even if the exact model of the CPU is known to the program.

Secondly, on modern pre-emptive multitasking operating systems, any given section of code may be paused at any point for small periods by the operating system as it allocates CPU resources to other tasks.  This means that not all of the clock ticks recorded will necessarily have been used by the code being observed.

These limitations have to be understood and the solution from a profiling point of view comes firstly from the observation that the the actual real time value isn’t important for comparing code. The number of clock cycles is, so changes to code that reduce the number of clock cycles required to perform a task are always going to yield a performance improvement, even if that cannot be precisely timed. The impact of the second problem can be reduced by attempting to quantify level of uncertainty in the observations recorded. This situation can be expressed mathematically in the following simple equation:

ObservedTicks = ActualTicks+Error

The actual clock cycles required for a given sequence of instructions are invariant. Therefore if multiple observations are made it follows that:

ObservedTicksmin = ActualTicks+Errormin

This implies that the error can be minimised by increasing the number of observations until there is no further reduction in the minimum observed count.  At this point, the error is either zero or some residual constant which can’t be altered from within our code anyway. This means that whilst a single measurement cannot be relied upon for profiling, an appropriately sized set of observations can give a useful benchmark value.

To be able to profile my own Free Pascal code, I have developed a small unit to make use of the rdtsc instruction. It contains 32 and 64 bit Intel assembler so that it can be used on both the 32 and 64 bit versions of the compiler with no operating system dependencies (It has been tested on Windows, Linux and Mac OS X). An example of its use is shown in the following code snippet:


Procedure DrawImage;
Begin
  CPUTimer.Start;
  Canvas.Draw(0, 0, ImageBuffer);  { The code being profiled. }
  CPUTimer.Stop;
  WriteLn('Image Draw Time: '+CPUTimer.MegaCountAsText+'MTicks');
End;

The timer is created as a singleton global object, so it does not need to be created or freed. There are three helper methods that return the tick count as text. Given that these values can often be very large numbers, two of these output routines perform divisions on the count by 1,000 and 1,000,000 respectively to make display more manageable.

Given that the code is quite short I have pasted it here in full:

Unit CPUTime;

{$IFDEF FPC}
  {$ASMMODE INTEL}
  {$MODE OBJFPC}
  {$LONGSTRINGS ON}
{$ENDIF}

Interface

Uses
  Classes, SysUtils;

Type TTickUnits = (tuTicks, tuKiloTicks, tuMegaTicks);

Type
  TCPUTimer = Packed Object
    StartTick: Int64;
    TickCount: Int64;
    Function FormatTickCount(Count: Int64; Units: TTickUnits = tuTicks; ShowUnits: Boolean = False): String;
    Function KiloCountAsText: String;
    Function MegaCountAsText: String;
    Function TickCountAsText: String;
    Procedure Mark; Assembler;
    Procedure Start; Assembler;
    Procedure Stop; Assembler;
  End;

Var
  CPUTimer: TCPUTimer;

Implementation

Function TCPUTimer.FormatTickCount(Count: Int64; Units: TTickUnits = tuTicks; ShowUnits: Boolean = False): String;
Var
  DisplayTicks: Int64;
  UnitSuffix: String;
Begin
  UnitSuffix := EmptyStr;
  Case Units Of
  tuTicks:
    Begin
      DisplayTicks := Count;
      If ShowUnits Then
        UnitSuffix := 't';
    End;
  tuKiloTicks:
    Begin
      DisplayTicks := Count div 1000;
      If ShowUnits Then
        UnitSuffix := 'Kt';
    End;
  tuMegaTicks:
    Begin
      DisplayTicks := Count div 1000000;
      If ShowUnits Then
        UnitSuffix := 'Mt';
    End;
  End;
  Result := IntToStr(DisplayTicks div 1000)+UnitSuffix;
End;

Function TCPUTimer.KiloCountAsText: String;
Begin
  Result := FormatTickCount(TickCount, tuKiloTicks, True);
End;

Function TCPUTimer.MegaCountAsText: String;
Begin
  Result := FormatTickCount(TickCount, tuMegaTicks, True);
End;

Function TCPUTimer.TickCountAsText: String;
Begin
  Result := IntToStr(TickCount);
End;

Procedure TCPUTimer.Mark; Assembler; NoStackFrame;
Asm
  {$IFDEF CPU64}
  mov rcx, Self
  rdtsc
  shl rdx, 32
  or rax, rdx
  sub rax, rcx[StartTick]  
  mov rcx[TickCount], rax
  {$ELSE CPU32}
  mov ecx, Self
  rdtsc
  sub eax, ecx[StartTick]  { Subtract low 32bits first. }
  sbb edx, ecx[StartTick+4]  { Subtract high 32bits with borrow. }
  mov ecx[TickCount], eax
  mov ecx[TickCount+4], edx
  {$ENDIF CPU64}
End;

Procedure TCPUTimer.Start; Assembler; NoStackFrame;
Asm
  {$IFDEF CPU64}
  mov rcx, Self
  rdtsc
  shl rdx, 32
  or rax, rdx
  mov rcx[StartTick], rax
  {$ELSE CPU32}
  mov ecx, Self
  rdtsc
  mov ecx[StartTick], eax
  mov ecx[StartTick+4], edx
  {$ENDIF CPU64}
End;

Procedure TCPUTimer.Stop; Assembler; NoStackFrame;
Asm
  {$IFDEF CPU64}
  mov rcx, Self
  rdtsc
  shl rdx, 32
  or rax, rdx
  sub rax, rcx[StartTick]
  mov rcx[TickCount], rax
  mov rcx[StartTick], 0
  {$ELSE CPU32}
  mov ecx, Self
  rdtsc
  sub eax, ecx[StartTick]  { Subtract low 32bits first. }
  sbb edx, ecx[StartTick+4]  { Subtract high 32bits with borrow. }
  mov ecx[TickCount], eax
  mov ecx[TickCount+4], edx
  mov ecx[StartTick], 0
  mov ecx[StartTick+4], 0
  {$ENDIF CPU64}
End;

End.


FreePascal 2.7.1 on Raspberry Pi

[EDIT: Please look here for more up-to-date instructions for Free Pascal 3.1.1 with Lazarus 1.7]

Since I wrote my original article about building FreePascal with Lazarus on the Raspberry Pi there have been a lot of developments.  One of the challenges with this platform is that the rapid pace of change very quickly makes a published set of instructions obsolete. This is now true of the previous scripts I have released which will not build the current trunk source code.

In my last post I covered how I now connect to the Pi from my laptop, which I find a lot more convenient.  In this post I will explain the current method I am using to build an up-to-date FreePascal compiler from the source code available from the official subversion repository.  Whilst the original compiler I built still works on the current release of Raspian, it does not contain many of the recent advances made by the FreePascal developers over the last year, or so.  The good news is that they have added a lot of new features that improve the quality of code generation for ARM chips.  This work has been the result of a concerted effort to support Android devices, but it also benefits developers wanting to target Raspberry Pis, making it a very attractive development language for the Pi.

The standard method for installing FreePascal from the Raspian repositories still works as Debian administrators would expect:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install fpc

However, this installs FreePascal 2.6.0. and since the current stable release is 2.6.4 this is now looking very dated.  The current development release, the one with the useful new features, is 2.7.1.

The source code for 2.7.1 can be downloaded using subversion, which needs to be installed before attempting to follow these instructions:

 sudo apt-get install subversion

The source code can then be retrieved using the following command.  I create a folder called FreePascal that I used to contain the various sources I use and the following command should be executed from there:

svn co http://svn.freepascal.org/svn/fpc/trunk 2.7.1

Also, if you are using a new install of Raspian, the default 2GB partition size is far to small for building FreePascal, I would recommend resizing the partition to take advantage of any additional space available on your SD card using the ‘raspi-config’ utility.

To be able to build 2.7.1, the required seed compiler is currently 2.6.4.  So to do this properly, we would need to build several sucessive releases of FreePascal to match these build requirements, which would be a very time consuming process.  Fortunately, I am not the only person interested in building FreePascal on the Pi; a very useful recent contribution was made by Thaddy de Koning.  He has built a 2.7.1 seed compiler which he has published here.  It is currently only a month old and he has also detailed the build method he uses here, the actual make command he uses is:

sudo make clean all distinstall OPT="-dREVINC -dFPC_ARMHF -CX 
-CpARMV6 -CfVFPV2 -CaEABIHF -OpARMV6 -O2 -OoFASTMATH -XX -Xs"

This assumes there is the required 2.6.4 compiler installed.  This is clearly not the case if you have a bare Raspian image installed.  Fortunately you can pass an option to the make script indicating the location of an unistalled seed compiler.  I extracted Thaddy’s actual compiler binary ‘lib/fpc/2.7.1/ppcarm’ from the above archive and copied it to my FreePascal working folder on the Pi.  I also renamed it ‘thaddyppcarm’ to avoid confusion once I start creating my own copies of this file.

Unfortunately, whilst trying to execute this process, I ran into a couple of problems. Firstly, as mentioned, the current make scripts expect 2.6.4 as the seed compiler.  Since Thaddy’s is later than this there is no problem with using it, except that the make script now performs version checking.  This can be suppressed by adding ‘OVERRIDEVERSIONCHECK=1’ to the command line.  The second problem was that the build process would halt with the following error:

Fatal: Can not open include file "revision.inc"

I don’t know why this should fail, or what the expected behaviour should be, but I found that process would complete successfully if the ‘REVINC’ option was removed from the command line.  So the actual make command that worked for me was:

sudo make clean all distinstall OPT="-dFPC_ARMHF -CX -CpARMV6 
-CfVFPV2 -CaEABIHF -OpARMV6 -O2 -OoFASTMATH -XX -Xs" 
OVERRIDEVERSIONCHECK=1 FPC=/home/pi/FreePascal/thaddyppcarm

Incidentally, the other options on this command line enable the additional processor support I mentioned earlier.  Most notably ‘FPC_ARMHF’ enables hardware floating point which will make a huge difference to the performance of computationally intensive programs.

To install the new compiler to its usual location I then use the same sequence of commands as given in the original scripts.  So copying the compiler and recreating it’s global symlinks requires:

sudo make install PP=compiler/ppcarm PREFIX=/usr
sudo rm -f /usr/bin/ppcarm
sudo ln -s /usr/lib/fpc/2.7.1/ppcarm /usr/bin/ppcarm

After which you will need to do the same for the compiler source:

sudo make install sourceinstall PREFIX=/usr
sudo rm -f /usr/share/fpcsrc
sudo ln -sf /usr/share/src/fpc-2.7.1/fpc /usr/share/fpcsrc

Lastly the fpc configuration file needs to be created with:

sudo /usr/lib/fpc/2.7.1/samplecfg /usr/lib/fpc/2.7.1 /etc

After completing all of this you should have a fully installed FreePascal Arm 6 compiler with hard float support.  The screen shot below shows this compiler being used to build a test X11 program which ran successfully on the Raspberry Pi over an SSH connection from my laptop:

FreePascalCommandLine

I have also updated the original build script to automate this process of rebuilding the compiler from the main subversion repository and it is available for download here.  At the moment, I do not need Lazarus on the Raspberry Pi, but it should be possible build it following my original instructions using this compiler instead.  One further thing to note; if you have not installed the fpc 2.6.0 from the repository, you will not have some of the required developer packages installed and will therefore have to install these manually.  For example the X11 test program cannot be linked without installing the ‘xorg-dev’ package with:

sudo apt-get install xorg-dev

 

Return to the Raspberry Pi!

Since I published my last post on the fencing score box system I have been contacted by a hardware manufacturer who is interested in embedding a Raspberry Pi in their new range of equipment.  As a result, this has put the Pi firmly back on my agenda!  I will return to the build process for the FreePascal compiler in another article, but before then I want to cover the method I am now using to connect to the Pi as I think it is far more convenient for a developer, than having the Pi set-up with a dedicated screen, keyboard and mouse.

The basic idea is to create a local subnet via a direct cable connection to the Pi and then interact with the Pi via SSH using the laptops own peripherals.  There are quite a number of ways of doing this, but I will describe the process I use as I think it is the simplest to set-up (at least from an Kubuntu/Ubuntu point of view).  To start with the Pi needs to be attached to a power source.  This can be a micro-USB mains charger, or a USB to micro-USB cable to draw the power off the laptop.  If you choose the second method, be sure your laptop is capable of reliably supplying the additional current required.  I prefer to power the Pi independently, to avoid any issue with straining my already hot laptop PSU.

Next the Pi is connect to the laptop via a standard Ethernet cable.  A cross-over cable is not required as the Pi is smart enough to detect this type of connection and reconfigure itself accordingly.  Once plugged in, you will need to know the IP address allocated to the Pi to be able to communicate.  This is where the confusion begins.  There seem to be four approaches to doing this.  Two require editing configuration files on the PI itself.  As with any editing of configuration files, it is always a wise precaution to make a backup copy of the file before making changes!  To edit configuration files on the Pi, I plugged the Raspian SD card directly into my laptop and edited it there before re-inserting it into the Pi.

The first way to allocate an IP address is to edit the ‘/etc/network/interfaces’ file on the Pi to define a static address for the eth0 interface.  This is the first method I tried, but I could not get this to work.  I suspect there are other start-up processes on the Pi that override this Linux configuration method.

After a bit more googling I found the second method.  It is also possible to pass a boot command line argument to the Pi that allocates an IP address.  This is achieved by editing the ‘cmdline.txt’ file in the boot partition of the Pi by adding ‘ip=169.254.0.1’, for example, to the end of this file.  Care must be taken not to insert a return as this must be all on one line.  This enabled a basic SSH connection to the Pi with the command ‘ssh pi@169.254.0.1’. However, the Pi was isolated from the wider network by the host laptop, so for example: ‘sudo apt-get update’ would not connect to the repositories.

The last two solutions solve this problem.  One is to set-up the laptop as a full-blown DHCP server.  This is certainly possible, but I feel it is overkill for what I wanted to achieve.  The last solution is to use internet connection sharing on the laptop, to allow network traffic to be passed through the laptop’s network connections.  My laptop uses an internal WIFI card to connect to our home ADSL rooter, or at work, the company’s wireless network.  This leaves the Ethernet port free to connect to the Pi. Internet connection sharing, permits traffic to be passed from one interface to the other.  In Kubuntu, and I believe Ubuntu also, this can quickly be set through the network connection editor.

ConnectionPropertiesThe default mode for cable connections is ‘Automatic’ on the ‘IPv4’ tab.  Changing this to ‘Shared to other computers’ sets up the interface for internet connection sharing.  I also set the option to ignore ‘IPv6’ connections as I did find an article which suggests this can cause problems with a Pi, although I don’t know if that is really required.  I also switched off automatic connection as I want to be able to manually choose between this and a standard DCHP connection.

ConnectionEditor

I also discovered that once internet sharing was enabled, it was not necessary to set the boot parameter IP address as one was allocated anyway.  In my case it was ‘10.42.0.44’. This can be discovered with the arp command.  Knowing this, I then edited the ‘/etc/hosts’ file on my laptop to look like this:

127.0.0.1 localhost
127.0.1.1 laptop01
10.42.0.44 rpi

# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

This enabled the SSH command to connect using the name ‘rpi’ rather than having to remember the IP address.  Its worth pointing out two useful features of SSH for those that are new to it.  The first is the ‘-X’ parameter.  This enables remote X Windows applications to be started over SSH.  The second is that modern Linux desktops can use it as a networking protocol to provide remote folders in their visual file managers.

Desktop

In this screenshot I have started the Pi’s Midori browser via an X Windows link and opened a Dolphin file browser looking at the Pi’s FreePascal folder.  So for Linux the full SSH command line for the default pi user looks like this:

ssh -X pi@rpi

Its worth mentioning for Windows users, that they can also use SSH by installing a utility called Putty.  I have not used this myself, but I have read several articles where this has been successfully used to achieve the same working environment as this.  At some point, I will also investigate using RSA keys which may be combined with SSH to avoid having to use passwords every time you connect.

Software Fencing Score Box

I have just started a new open source project to create a fencing score box system.  The idea is to use an old laptop or other low cost system to emulate the hardware of an electric fencing score box.  My son has been competitively fencing for just over a year now and I have been looking for an affordable way of enabling him to train at home.  The best value for money system I have come across is the one used by his coach, the Epee Hitmate.

However, that is still somewhat out of our price range at present.  As a result, I have started investigating the possibility of emulating the control box hardware with software and then interfacing this to the actual weapon switches.  The ideal solution would be to connect wirelessly to something like the HitMate’s transmitter units, but failing that a conventional wire spool connection would do.

I have also noticed that fencing referees are increasingly using smart-phone apps to run bouts and I thought it would be an interesting exercise to see if a smart-phone could be used as a remote control for such a project.  To avoid having to develop a version for each OS, I decided to embed a small webserver so that any mobile browser app could be used as the controller.  The screen shot below shows this running on an iPhone simulator:

iPhoneBrowser

For those unfamiliar with fencing, the basic information is quite simple:  there is a score for each fencer, one to the left of the referee (red) and one to the right (green) and there is also a count down of the time remaining in the current bout.  The buttons enable the referee to start and stop the timer and adjust the scores for left and right.

The main program is a conventional application written in FreePascal.  This can be compiled to run on Linux or Windows (and possibly a Mac as well!) and has no external dependencies, although you can add an optional WAV file if you want a buzzer to sound during a hit. The following screenshot shows this running on Linux :

RaspberryPi

In fact, the keen eyed amongst you will probably have noticed the little perspex box and realised this is actually running on a Raspberry PI!  This was compiled with the PI FreePascal compiler I created last year.  To be honest, I haven’t done anything with the RPI since then as, until now, I had not thought of a practical use for it.  However, the PI is actually an ideal platform for this project.  Also the world of FreePascal on the PI has moved on tremendously and there really isn’t any need to build the compiler from source now.  Further more, Thaddy de Koning has created a Pascal interface for the PI’s OpenVG library, giving access to the powerful GPU for 2D graphics.  This will go a long way to compensate for the PI’s somewhat underpowered CPU.

So if you would like to take a look at this project, it is available on Bitbucket:

https://bitbucket.org/PaulFMichell/allez/

A pre-compiled windows binary is available here:

https://bitbucket.org/PaulFMichell/allez/downloads/Allez.exe

If you want to test the embedded webserver it  connects on port 8080 to aviod clashing with any other webserver that might be running on the default port 80.  So to access it on the local machine requires the following URL:

http://localhost:8080/

This is still very much a test system and it is a long way from being a completed project. However, it does demonstrate some of the capabilities of FreePascal and will serve as a good starting point for a more focused endeavour and if there are any Fencing – Electronics – Raspberry PI enthusiasts out there who have any bright ideas about linking the weapon switches, I would love to hear from you!