Faster panning and zooming lazarus / 39-Graphics ---------------------------------------------------------------------- big_M · 2020-10-06 22:28 So, in my program I need to zoom and pan larger images. Currently I do that this way (using standard components): When I zoom, I generate a larger version of the image with stretchdraw. When panning (zoomed in) I then read a part of the larger image with copyRect. Is this generally a good idea, or is there a better approach? The problem is that this runs not fast enough. When I zoom in (2x) on a not very large image (1800*1400px), panning gets already sluggish. With larger images it gets unusable. Would the use of BGRABitmap give me any benefits in that regard? ---------------------------------------------------------------------- VTwin · 2020-10-07 02:47 What graphics are you using? BGRABitmap is impressively fast even with large images. ---------------------------------------------------------------------- Handoko · 2020-10-07 03:24 TCanvas is it is for maximum compatibility for all hardware, not optimized for performance. So it does not use all the features of your VGA. Nowadays, almost all even the integrated VGAs have some basic hardware acceleration and support at least OpenGL version 1.5/2.0. If you do graphics processing and performance is important, you should choose a graphics library that supports hardware acceleration: https://wiki.freepascal.org/Graphics_libraries Learning a new library is hard you should choose wisely, not all libraries in the link above are hardware accelerated. Graphics32 is not hardware accelerated but you still will get some performance increase because they optimize the code properly. If you want to get the maximum performance you should learn OpenGL, the hardest. Simply drawing a triangle requires you to write plenty of lines. You can use OpenGL in Lazarus via TOpenGLContext. Here are the documentation and a compile-able demo of using TOpenGLContext: https://wiki.lazarus.freepascal.org/OpenGL_Tutorial https://forum.lazarus.freepascal.org/index.php/topic,35850.msg238019.h tml#msg238019 BGRABitmap support OpenGL but it is only enabled in 3D functions not in all drawing functions. Quote from: VTwin on October 07, 2020, 04:47:20 amBGRABitmap is impressively fast even with large images. TBGRABitmap is slow if you do large image stretching/resizing and animation. On small images, it is okay. ---------------------------------------------------------------------- big_M · 2020-10-07 10:29 Okay, so according to the wiki Graphics32 doesn't work on Linux, is that correct? That would be a shame. The problem with TOpenGLContext is that, as far as I understand, I have to do everything myself with very basic graphics operations. So I can't easily draw text for example. Tbh, I think this is going to be overkill for my software. So, you think TBGRABitmap is overall not faster than TCanvas then? Andorra 2D looked interessting too, but that seems to be dead since 10 years ---------------------------------------------------------------------- circular · 2020-10-07 11:23 Quote from: Handoko on October 07, 2020, 05:24:23 amBGRABitmap support OpenGL but it is only enabled in 3D functions not in all drawing functions.No no you can use BGRABitmap for 2D OpenGL. QuoteTBGRABitmap is slow if you do large image stretching/resizing and animation. On small images, it is okay.Indeed if you do a fine resample, it is slow. Though if you do a simple stretch, speed is ok. You can as well to a StretchPutImage that will stretch only the visible part. ---------------------------------------------------------------------- winni · 2020-10-07 11:24 Hi! BGRAbitmap is definitly faster than TCanvas. The people are often forgetting with what a high amount of data they are working with images. An Image with 1280 x 1024 Pixel  has 1.310.720 Pixels For simple operations you have to touch every of the 4 Channels RGBA. That are 5.242.880 Operations. If you write a simple filter and use  only the 8 neighbor pixels then you are at 42 million operations. Think about it Winni If yo ---------------------------------------------------------------------- circular · 2020-10-07 11:26 Quote from: big_M on October 07, 2020, 12:29:01 pmThe problem with TOpenGLContext is that, as far as I understand, I have to do everything myself with very basic graphics operations. So I can't easily draw text for example. Tbh, I think this is going to be overkill for my software. So, you think TBGRABitmap is overall not faster than TCanvas then? You can use for example a TBGRAVirtualScreen and in the redraw even a StretchPutImage. This is more or less what LazPaint does. You can as well use BGRABitmap with OpenGL. In this case, drawing is not too complicated and you can draw text as well. See example: https://github.com/bgrabitmap/bgrabitmap/tree/master/test/test4lcl_ope ngl ---------------------------------------------------------------------- circular · 2020-10-07 11:29 Quote from: winni on October 07, 2020, 01:24:08 pmBGRAbitmap is definitly faster than TCanvas. Not necessarily. If you have a TBitmap and do a StrecthDraw, it may use hardware acceleration and thus be quicker than BGRABitmap. Though you have less control over what you do. For example, you cannot choose the resample quality with Canvas. ---------------------------------------------------------------------- circular · 2020-10-07 11:31 Quote from: big_M on October 07, 2020, 12:28:59 amWhen I zoom, I generate a larger version of the image with stretchdraw. When panning (zoomed in) I then read a part of the larger image with copyRect. Is this generally a good idea, or is there a better approach? I guess whatever library you are using, this is not a good approach because you need a lot of memory to store the scaled image. To avoid that, you can do a StretchDraw directly on the Canvas with the appropriate coordinates (for example with negative X and Y if the top- left of the image is not visible). ---------------------------------------------------------------------- big_M · 2020-10-07 13:19 Quote from: circular on October 07, 2020, 01:31:30 pmI guess whatever library you are using, this is not a good approach because you need a lot of memory to store the scaled image. To avoid that, you can do a StretchDraw directly on the Canvas with the appropriate coordinates (for example with negative X and Y if the top-left of the image is not visible). Yes, I thought about something similar as an alternative. However then I would have to strechdraw constantly when panning, which I guess would be slower than just reading from an already scaled image. Or I can of course do the strechdraw only after the panning, and live with blank areas during the panning. Not nice, but it would certainly do the job. But I would prefer to avoid that of course ---------------------------------------------------------------------- avra · 2020-10-07 13:23 Quote from: big_M on October 07, 2020, 12:29:01 pmOkay, so according to the wiki Graphics32 doesn't work on Linux, is that correct?No. Take a look at https://www.pilotlogic.com/sitejoom/index.php/wiki.html?id=198. pl_Graphics32 was tested on Win/Lin/BSD/Sol/Mac/GTK2/QT4/QT5/x86/x86_64/Arm/Arm64 ---------------------------------------------------------------------- circular · 2020-10-07 13:40 Quote from: big_M on October 07, 2020, 03:19:09 pmYes, I thought about something similar as an alternative. However then I would have to strechdraw constantly when panning, which I guess would be slower than just reading from an already scaled image. Or I can of course do the strechdraw only after the panning, and live with blank areas during the panning. Not nice, but it would certainly do the job. But I would prefer to avoid that of course I invite you to try StretchDraw directly, you will see it is not slow. Alternatively what you could do is divide the image according to a grid and precompute the scaled image for visible tiles and free them as they become invisible. ---------------------------------------------------------------------- Handoko · 2020-10-07 14:12 See the image below for a comparison of sample quality: rmSimpleStretch vs rmFineResample. Can you notice any difference? Most people can't tell the difference. But all graphics professionals can tell you the difference. If you can tolerate that quality then you can use rmSimpleStretch. When writing CATWW I done some tests for the BGRABitmap's performance. The time for painting the whole screen that composed of several scaled and rotated transparent layers using rmFineResample was about 200 ms but rmSimpleStretch was only about 50 ms. I also found if the image was about 300 x 300 pixels and larger then it started to have noticeable performance issue. With heavy use of caching, my CATWW finally can run on acceptable performance on old Core2 Duo machines. It 'eats' about 100 MB for the caching the images but I think it's okay because computer memory is now very affordable. You can download test CATWW 0.2. Unfortunately the sample quality feature is not available on version 0.2. You can manually change it if you search into the code. https://forum.lazarus.freepascal.org/index.php/topic,50989.0.html Look at the picture below. Pay attention on the roundness of clock's border. Also, the quality is not good on thin font texts, on large and/or thick font there's almost no noticeable problem. ---------------------------------------------------------------------- big_M · 2020-10-07 16:20 The quality is not that important in this case, but I zoom in with x2-steps anyway, so the result is okay/good enough even with the very simple stretch that StrechDraw does.  I will try the method that circular has proposed now If it's not fast enough I will try it with BGRABitmap. Thank you so far! ---------------------------------------------------------------------- ChrisR · 2020-10-08 10:50 Can I suggest you try the OpenGL demo texture.lpr   https://github.com/neurolabusc/Metal-Demos/tree/master/texture by default, it loads the small. Coral and ClownFish bitmaps, but you can change these to be very large bitmaps. Dragging the mouse pans the images, and the scroll wheel adjusts the zoom. The nice thing about OpenGL is that the bitmap is stored in the GPU RAM, not the CPU RAM. This means that panning and zooming does not face the memory wall of slow transfer speeds. The font_gl project demonstrates how to have nice scaleable fonts with OpenGL:   https://github.com/neurolabusc/Metal-Demos/tree/master/font ---------------------------------------------------------------------- big_M · 2020-10-11 11:51 Okay, so I have tried some things. StrechDraw is indeed very fast, however it seems like I found the real culprit, which looks to be the reading speed. The problem is that reading even only a small portion of a big image takes very long, at least with TCanvas. Tiling the image into 200x200px tiles, and reading only the needed ones looks promising so far. Quote from: ChrisR on October 08, 2020, 12:50:19 pmCan I suggest you try the OpenGL demo texture.lpr   https://github.com/neurolabusc/Metal-Demos/tree/master/texture by default, it loads the small. Coral and ClownFish bitmaps, but you can change these to be very large bitmaps. Dragging the mouse pans the images, and the scroll wheel adjusts the zoom. The nice thing about OpenGL is that the bitmap is stored in the GPU RAM, not the CPU RAM. This means that panning and zooming does not face the memory wall of slow transfer speeds. The font_gl project demonstrates how to have nice scaleable fonts with OpenGL:   https://github.com/neurolabusc/Metal-Demos/tree/master/font Interesting links, thank you. ---------------------------------------------------------------------- marcov · 2020-10-11 13:36 I use opengl for that, and also draw on top of that. An awful ugly and old but functional demo is posted in this thread: ht tps://forum.lazarus.freepascal.org/index.php/topic,30556.msg194627.htm l#msg194627