0

Under delphi (and under firemonkey/android), What is the most fastest way to draw on a Tcanvas a TbitmapSurface ?

I try to use TTexture like MyTexture.Assign(aBitmapSurface) and later do TCustomCanvasGpu(Canvas).DrawTexture but MyTexture.Assign(aBitmapSurface) have 2 main drawbacks :

  1. it's must be done inside the main thread (i don't know why else we have black screen)
  2. it's relatively slow operation
zeus
  • 12,173
  • 9
  • 63
  • 184

2 Answers2

0

I do not use/code for Android so read with extreme prejudice. As Delphi uses VCL so I stick to it. If Delphi under Android does not then you can ignore this answer.

It looks like it is similar problem to Windows when accessing any OS visual stuff (does not matter if by GDI or WinAPI) from outside main thread will invalidate the OS API making weird things latter like random crashes, wrong rendering, etc. Another reason can be the use of GPU related calls which are usually bound to process/thread and device context. So to make it thread safe you could have to create shared context if possible if not you need to stick to main thread.

By Assign you are creating new image and copy the old to it that takes time comparable to drawing itself not to mention on devices with slow memory it can really slow down the whole thing considerably a lot more.

If you are dealing with VCL graphic components then try to use Draw directly:

  • blablabla->Canvas->Draw(x,y,aBitmapSurface);

if blablabla and aBitmapSurface are valid gfx components then it should work. As I mentioned not sure if this is present also in Android. The x,y is the position where you want to draw the aBitmapSurface. There is also StretchDraw if you need to rescale but that is a bit slower.

See Display an array of color in C sections GDI and GDI Bitmap for some ideas under VCL

Community
  • 1
  • 1
Spektre
  • 49,595
  • 11
  • 110
  • 380
  • unfortunatly it's not possible to do blablabla->Canvas->Draw(x,y,aBitmapSurface); i must first transform aBitmapSurface in TTexture and it's this that is slow because it's must be done from the main thread :( – zeus Jan 05 '16 at 09:52
  • @loki Try to use `Graphics::TBitmap` from VCL instead of `TbitmapSurface` if it is not fully compatible with VCL – Spektre Jan 05 '16 at 11:49
  • @loki no VCL stuff is but if you get the `ScanLine[]` pointers in own array then you have FAST multi-thread safe pixels access – Spektre Jan 05 '16 at 16:21
  • not sure the draw to to the canvas via the pixel array will be fast enalf :( i will make a try first :) – zeus Jan 07 '16 at 09:20
  • @loki I use it for multi-threaded Software 3D back ray tracing with multi-spectral rendering engine of mine so it is fast enough if coded right. But of coarse can not compete with on board geometry rendering on GPU. The trick is to read `ScanLine[]` only once after resizing of TBitmap and then use just your own pointer array variables ... – Spektre Jan 07 '16 at 09:25
0

TBitmapSurface is in system memory so you need to assign your TBitmapSurface to a TBitmap first, to be converted to native OS bitmap (or texture) format that FMX uses for drawing:

bmp.Assign(surf);

Then draw the Bitmap to the canvas:

canvas.BeginScene();
canvas.DrawBitmap(bmp, SrcRect, DstRect, AOpacity);
canvas.EndScene();

I have tested it on Windows and Android. On android you need to call the Repaint too see the change.

piXelicidio
  • 187
  • 9