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 :
it's must be done inside the main thread (i don't know why else we have black screen)
it's relatively slow operation
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
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.
Related
I'm implementing my custom View where I override onDraw() method in order to draw some set of objects.
The objects are supposed to be placed in a coordinates which are evaluated in a particular way. The code placing those objects works incorrectly (some of them are either not drawn at all or are overlayed by other objects) so that I need to do some debugging to execute it line-by-line and watch what is actually being drawn step-by-step.
However as far as I understand the actual picture is shown on the screen after all the drawing is completed since when I'm executing canvas.drawBitmap line nothing is appearing on my emulator's screen.
My question is: What is the best (or maybe the only) way to debug onDraw() code? I did some research in Adroid dev portal and here in posted questions but was unable to find the solution.
Haven't tried this, but it should put you on the right track:
At the start of your onDraw method, make a new Bitmap using the width and height from the canvas
Make a new Canvas from the Bitmap
Run your draw calls on this Canvas
You can inspect the Bitmap from the Android Studio debugger, and will update with every draw call
If you also want to draw the data to the screen, you can use drawBitmap on the original Canvas with your full Bitmap, but this shouldn't be needed for debugging
Don't leave this in production code
#Override
public void onDraw(Canvas canvas) {
Bitmap screenBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
Canvas screenCanvas = new Canvas(screenBitmap);
/* Run draw calls on screenCanvas, inspect screenBitmap for result*/
}
I'm not an expert, but I know graphics acceleration in nowadays Android is quite complex: drawing commands are recorded in drawing lists, which are then optimized and handled to the GPU to be drawn. And, since Android 5.0, part of the drawing that needs to be handled in the CPU can (is always?) run in a background thread. See https://source.android.com/devices/graphics/ for general background.
Then, about the tools, I would suggest using systrace. For more information and a detailed example on how to use it and more tools, see the excellent (albeit probably a bit outdated) article by Romain Guy "Android Performance Case Study" and the follow-up "Android Performance Case Study Follow-up".
Also, see Android documentation "Perfect GPU Use".
Hope this sets you in the right path. This is a very complex subject.
You can try commenting the suspicious statements.
Another option would be to use a timer - Frequently invalidate the view from a different thread and inside onDraw run different statements only if some time has elapsed. Use different time for different statements, so that it looks like an animation.
I'm working on a university project in which I need to visualize on a smartphone datas from pressure sensors built in an insole.
I need to draw on a View, as a background, a footprint, something like the image below but just for one foot.
I don't want to use a static image because with different screens resolution it could lose too much quality, so I'm trying to do it by code.
The main problem is that I'm not very skilled in graphic programming so I have not a smart approach to this problem.
The first and only idea that I had was to take the insole's CAD representation, with its real dimensions, scale it in function of screen's ones and put it together using simple shapes (arc, circle, ecc...) available in Android.
In this way I'm creating a Path which will compose the whole footprint, once I will draw it with a Canvas.
This method will let me to do the work but is awful and needs an exceptional amount of work and time to set every part.
I have searched for some similar questions but I haven't found anything to solve my problem.
Is there (of course there is) a smarter way to do this stuff, saving time and energies?
Thank you
of course, you can always use open gl es
this method might not save your time and energy but will give you a better graphic and scope to improve it for later purpose
the concept is to create a float buffer with all the points of your footwear and then draw is with connected lines on a surfaceView
to get started with open gl es you can use this tutorial : https://developer.android.com/guide/topics/graphics/opengl.html
and here is an example : https://developer.android.com/training/graphics/opengl/index.html
I would like to create a Canvas instance that is too big to be backed by a heap memory Bitmap, lets say 5000x5000 pixels (approx. 95MB). I would like this very large Canvas to send all the various draw operations directly to a bitmap file. Unfortunately the Bitmap class in Android is marked final so I can't provide my own implementation. Does anyone have an idea if and how this might be accomplished? I'm not very interested in performance, 10 seconds to write make a few dozen draw operations is fine, the goal is to not get out of memory errors.
There's no facility to provide the function you are asking, and even if there were, to do such operations to a file would provide horrendous performance.
Probably the only reasonable way is to only store the drawing operations, and create a Canvas that is the same size as the device screen that would serve as a "window" into the while 5000x5000 pixel canvas. For detailed explanation see my answer to a related question here: Android - is there a possibility to make infinite canvas?
Here is an idea I had that I think could theoretically work, but would probably require far too much effort:
Create a subclass of Canvas that contains many smaller Canvas objects inside it. These would represent tiles of the overall Canvas. These tiles should be small enough to fit in memory at least one at a time. Create one file for each inner tile Canvas and use it to store uncompressed pixel data from a Buffer.
When a draw operation occurs on the overall Canvas figure out which tiles need to be drawn to. One at a time read the file for that tile into a Bitmap in memory and perform the possibly clipped draw and then save the Bitmap data back to the file and close it.
Theoretically it sounds possible, realistically it sounds like too much work.
I'm developing an Android game using Canvas element. I have many graphic elements (sprites) drawn on a large game map. These elements are drawn by standard graphics functions like drawLine, drawPath, drawArc etc.
It's not hard to test if they are in screen or not. So, if they are out of the screen, i may skip their drawing routines completely. But even this has a CPU cost. I wonder if Android Graphics Library can do this faster than I can?
In short, should I try to draw everything even if they are completely out of the screen coordinates believing Android Graphics Library would take care of them and not spend much CPU trying to draw them or should I check their drawing area rectangle myself and if they are completely out of screen, skip the drawing routines? Which is the proper way? Which one is supposed to be faster?
p.s: I'm targeting Android v2.1 and above.
From a not-entirely-scientific test I did drawing Bitmaps tiled across a greater area than the screen, I found that checking beforehand if the Bitmap was onscreen doesn't seem to make a considerable different.
In one test I set a Rect to the screen size and set another Rect to the position of the Bitmap and checked Rect.intersects() before drawing. In the other test I just drew the Bitmap. After 300-ish draws there wasn't a visible trend - some went one way, others went another. I tried the 300-draw test every frame, and the variation from frame to frame was much greater than difference between checked and unchecked drawing.
From that I think it's safe to say Android checks bounds in its native code, or you'd expect a considerable difference. I'd share the code of my test, but I think it makes sense for you to do your own test in the context of your situation. It's possible points behave differently than Bitmaps, or some other feature of your paint or canvas changes things.
Hope that help you (or another to stumble across this thread as I did with the same question).
I have a drawing app where the user can draw lines with their finger, adjust the color, thickness, etc. As the user is drawing, I am converting the massed X/Y points from MotionEvent into SVG Paths, as well as creating Android Path's and then drawing the Android Path's to the screen via a Canvas, and committing the SVG Path's to the app's database.
I am following the model used in FingerPaint, in that the 'in progress' lines are drawn on the fly by repeated calls to invalidate() (and thus, onDraw()), and once the line is complete and a new line is started, the previous line(s) are drawn in onDraw() from the underlying Canvas Bitmap, with in progress lines again generating repeated re-draws.
This works fine in this application - until you start rotating the underlying Bitmap to compensate for device rotation, supporting the ability to 'zoom in' on the drawing surface and thus having to scale the underlying Bitmap, etc. So for example, with the device rotated and the drawing scaled in, when the user is drawing, we need to scale AND rotate our Bitmap in onDraw(), and this is absolutely crawling.
I've looked at a SurfaceView, but as this still uses the same Canvas mechanism, I'm not sure I'll see noticeable improvement... so my thoughts turn to OpenGL. I have read somewhere that OpenGL can do rotations and scaling essentially 'for free', and even seen rumors (third comment) that Canvas may be disappearing in future versions.
Essentially, I am a little stuck between the Canvas and OpenGL solutions... I have a 2D drawing app that seems to fit the Canvas model perfectly when in one state, as there are not constant re-draws going on like a game (for instance when the user is not drawing I don't need any re-drawing), but when the user IS drawing, I need the maximum performance necessary to do some increasingly complex things with the surface...
Would welcome any thoughts, pointers and suggestions.
OpenGL would be able to handle the rotations and scaling easily.
Honestly, you would probably need to learn a lot of OpenGL to do this, specifically related to the topics of:
Geometry
Lighting (or just disabling it)
Picking (selecting geometry to draw on it)
Pixel Maps
Texture Mapping
Mipmapping
Also, learning OpenGL for this might be overkill, and you would have to be pretty good at it to make it efficient.
Instead, I would recommend using the graphic components of a game library built on top of openGL, such as:
Cocos2d
libgdx
any of the engines listed here
Well, this question was asked 6 years ago. Maybe Android 4.0 has not come up?
Actually, after Android 4.0 the Canvas at android.view.View is a hardware accelerated canvas, which means it is implementd by OpenGL, so you do not need to use another way for performance.
You can see the https://github.com/ChillingVan/android-openGL-canvas/blob/master/canvasglsample/src/main/java/com/chillingvan/canvasglsample/comparePerformance/ComparePerformanceActivity.java to compare the performance of normal canvas in view with GLSurfaceView.
You are right that SurfaceView uses Canvas underneath the hood. The main difference is that SurfaceView uses another thread to do the actual drawing, which generally improves performance. It sounds like it would not help you a great deal, though.
You are correct that OpenGL can do rotations very quickly, so if you need more performance that is the way to go. You should probably use GLSurfaceView. The main drawback with using OpenGL is that it is a real pain to do text. Basically you have to (okay, don't have to, but seems to be the best option) render bitmaps of text.