I have been studying Metal and to help, I used an old drawing app and converted the drawing layer to a MTKView. I got textures working using pdf images and they draw very well on the screen using Apple Pencil. The initial FPS is 120. But as I draw on the screen and begin filling it up with brush strokes, the FPS will gradually drop until it is well below 50 FPS. If I clear the canvas, the FPS goes back up to 120 and the issue will repeat. Here is the basic method I am using that I have found in other drawing app code:
TouchesBegan I begin the vertices
TouchesMoved I append vertices and draw primitives using point with the vertices count, then setNeedsDisplay is called and I present and commit the drawable
TouchesEnded is same as moved, but then clear the vertices
Why is the FPS drop happening? I presume because it is redrawing the entire view every frame and the textures have alphas. Is there a method I could use to maintain the FPS throughout the life of the drawing?
TouchesBegan I begin the vertices
TouchesMoved I append vertices and draw primitives using point with the vertices count, then setNeedsDisplay is called and I present and commit the drawable
TouchesEnded is same as moved, but then clear the vertices
Why is the FPS drop happening? I presume because it is redrawing the entire view every frame and the textures have alphas. Is there a method I could use to maintain the FPS throughout the life of the drawing?
There could be a number of reasons performance decreases as the vertex sound increases. Are you calling draw[Index]Primitives to render each stroke.
The idea of only drawing what necessary by saving the current state makes a lot of sense. Instead of taking a snapshot with UIImage, I would render to an offscreen texture and maintain that as your canvas without clearing. Then, for each frame you can copy that texture to a drawable.
As a bonus, if you're using MTKView, to make your app more efficient so that you're only drawing frame when a new stroke has been added I would enableSetNeedsDisplay to YES so that you only draw when an touch event occurs and you need to update the canvas.
Since this is an exercise in learning Metal, this would be a good opportunity to familiarize yourself with the performance analysis tools. I suggest firing up Xcode Instruments and choose the "Metal System Trace" template to create your project. With this you can see where your app is spending its time on the GPU with the "GPU" instrument and on the CPU with the "Time Profiler" instrument. This article should give you some ideas on using it. You can also find a number WWDC videos which demonstrate practical use of the tools including this one which gives a nice overview of the current state of the Metal tools.
The idea of only drawing what necessary by saving the current state makes a lot of sense. Instead of taking a snapshot with UIImage, I would render to an offscreen texture and maintain that as your canvas without clearing. Then, for each frame you can copy that texture to a drawable.
As a bonus, if you're using MTKView, to make your app more efficient so that you're only drawing frame when a new stroke has been added I would enableSetNeedsDisplay to YES so that you only draw when an touch event occurs and you need to update the canvas.
Since this is an exercise in learning Metal, this would be a good opportunity to familiarize yourself with the performance analysis tools. I suggest firing up Xcode Instruments and choose the "Metal System Trace" template to create your project. With this you can see where your app is spending its time on the GPU with the "GPU" instrument and on the CPU with the "Time Profiler" instrument. This article should give you some ideas on using it. You can also find a number WWDC videos which demonstrate practical use of the tools including this one which gives a nice overview of the current state of the Metal tools.