Two visible CATiledLayers causing problems! - iphone

This issue has been encountered by someone else, but I've not seen any solutions - see ( http://openradar.appspot.com/6941930 ).
I have a UIScrollView whose content view's layer contains two CATiledLayers. One tiled layer draws content quite fast (but long enough to make drawInRect: too slow!), the other draws them slowly.
The quicker CATiledLayer doesn't Zoom has has default LOD settings, with a large tile size.
The slower CATiledLayer is zoomable.
Using just one of the CATiledLayers behaves as expected.
The problem is adding both layers to the visible screen causes one or the other to behave slowly. Annoyingly, it seems to make the content that draws normally fast, much slower.
I've not seen a way yet to reliably know when one CATiledLayer has completed its draw.
I think the solution would be to queue the Tiled Layers, so draw the slower tiled layer when the quicker one has finished. But the documentation on CATiledLayer is pretty bad.
I've tried to use a NSTimer, and set it for a 3 second wait before drawing the 2nd Tiled Layer. This however does not seem to solve the problem! I'm lost!

CATiledLayer seems to favor any tiles near the center of the screen. Perhaps one of your layer's is closer to an edge?

Related

Best practices drawing onto a very large graphics context

I need to draw onto a very, very wide context (possibly going into the 100,000's of pixels in width)
The stuff that I am drawing is simple (exclusively lines, ellipses and arcs).
Currently, I am using a tiling mechanism to render pieces of this image as SVG graphics in UIWebViews sitting in a UIScrollView. Horrible, I know. Performance is so bad it makes me want to hurt myself.
So I'm left with no choice but to draw things directly in Quartz. The problem is that I couldn't find any good information on handling such a large drawing.
The commands will be stored in a array (i.e [0] - line from x1,x2 to y1,2 [2] - arc at x1,x2,h,v etc...) which makes it possible to immediately determine what needs to be drawn at any point of time.
How should I best go about handling the actual drawing? Make a ginormous context then draw onto it, erasing the parts that go off screen? Can I draw straight into the UIScrollView?
Or am I supposed to performing some sort of tiling? Creating smaller views and drawing on them?
Look into CATiledLayer. It supports huge dimensions, yet only draws "tiles" that are visible. This means that in your drawLayer:inContext: you need to calculate how to draw the tile you were asked to draw. That might be quite complicated to implement but the performance boost makes up for this. I use this to draw a "strip" that is often over 20.000 pixels wide, tiled into 256 pixel pieces (this is the default).
You not only want this because of speed but also due to memory: if you really had a view or layer that were that big it would take up immense amounts of memory. Tiling is the only solution here.
See this nice article by Michael Heyeck on how to use CATiledLayer (Apple has a demo as well, but I think the linked article is better).
If the stuff you are drawing is not static then using CATiledLayer(s) doesn't work very well. A better solution is presented partly in http://www.mlsite.net/blog/?p=1342 . I've used this as a basis from some interactive drawing. A little slow but I'm still optimizing. Use http://red-glasses.com/index.php/tutorials/catiledlayer-how-to-use-it-how-it-works-what-it-does/ as a check list of whether you should use CATiledLayer(s) or not.

ZoomingPDFViewer apple example

I'm trying to understand Apple's example code for the ZoomingPDFViewer. Here are some questions that I have in my understanding of how it works in my mind. I'm not really sure if I understand it correctly. The link for their code is at: http://developer.apple.com/library/ios/#samplecode/ZoomingPDFViewer/Introduction/Intro.html
(1) CATiledLayer is used to represent the PDF at different zoom levels. I'm assuming that's what this class is used for looking at the Class Reference. Would you ever use something else besides this class for a zooming function?
(2) in the initWithFrame for TiledPDFView, they do: tiledLayer.tileSize = CGSizeMake(512.0, 512.0); Is the tileSize the tiles that make up for the whole image? If so, why such a large size?
(3) How does the oldPDFView and pdfView work? Like which one is in front at the different stages of zoom, and when do they get swapped out. I'm having a hard time understanding the flow of the logic. Thanks.
(1) If you don't require the level of detail to vary for different zoom levels, or if the PDF loads fast enough to not warrant drawing a couple of tiles at a time, a regular UIView with a regular CALayer will work fine. For instance, if you were displaying an image instead of a PDF, and the image loads fast enough to not cause a performance snag, you would not need the asynchronous loading that CATiledLayer provides. The PhotoScroller sample uses both the tiled and non-tiled approaches if you want to compare them.
(2) The tileSize attribute changes the size of the blocks the layer should be split into. You can set this to whatever you want. 512x512 really isn't all that large, especially if your PDF dimensions are big. The default is 256x256.
(3) Anytime you start to zoom, oldPDFView is removed and released. Then pdfView is assigned to oldPDFView. When the zooming ends, a new pdfView is created with the change in scale and added on top of the old one. If the new scale is an increase, the new pdfView will be drawn with a higher level of detail. This makes it so you can zoom deeper and deeper into the PDF. The maximumZoomScale and minimumZoomScale only restrict how much you can zoom with an individual gesture.

Cocos2d Animation Flickering

I have a sprite which i animate using CCAnimate. the animation is composed of 4 spritesheets that i swap when needed. everything works pretty good except for some flickering when swapping spritesheets.
any ideas on what to do?
i've found a solution in case anyone is interested.
it seems theres a lag when switching between CCAnimation objects, that make the frame be blank for a split second. the solution is to manually set the sprite to the first frame of the coming animation immediately after ditching the old one.
more info here:
http://www.cocos2d-iphone.org/forum/topic/8729
Do you preload the spritesheets using CCTextureCache's addImage? If not, you'll notice a lag whenever you switch to a spritesheet for the first time.
Also, unless your spritesheets are so big that you can't fit all animations into a 1024x1024 texture you should simply put all of the sprites into one sheet, instead of using multiple like for example four 256x256 spritesheets. You hardly gain anything from doing that, at worst you lose the benefit of spritesheets because as soon as you render from two different spritesheets it'll be two draw calls instead of one. Texture atlases are not for organizing your animations but to keep as much as possible of all of your graphics into as few as possible textures.

OpenGL ES. Scrolling 3 layer starfield textures gets me from 60 -> 40 FPS

I need to draw the background for a 2D space scrolling shooter. I need to implement 3 layers of stars: one distant nebula (moving really slow) in the background, one layer of far away stars (moving slow) and one layer of close stars (moving normal) on top of the other two.
The way i first tried this was using 3 textures of 320 x 480 that were transparent pngs of the stars. I used GL_BLEND and SRC_ALPHA, ONE_MINUS_SRC_ALPHA.
The results were not great even on the 3GS. On the first generation devices the FPS dropped to 40..50 so i think i'm doing this the wrong way.
When i disable the GL_BLEND everything works great even on the 1st gen devices and the FPS is back to 60 again... so it's must be the fact that i'm trying to belnd large transparent textures.
The problem is i don't know how to do it some other way...
Should i draw only the first nebula like an opaque texture and then try to emulate the middle and top star layer with small points moving around the screen?
Is there any other approach on the blending issue? How can i speed up the rendering process? Is one big texture (tileset) the answer?
Please help me cuz i'm stuck here and i can't get out.
I don't know how you want your stars to look like, but you might want to try to move them from a texture to geometry by using GL_POINTS in the DrawElements or DrawArrays maybe just replace the top two layers with layers of geometry. You can manipulate the points using PointSize, PointSizePointerOES and PointParameter to modify the rendering of the points.
You might want to use multi-texturing to see if that speeds it up. Each multi-texture stage can be assigned a unique transformation matrix, so you should be able to translate each layer at different speeds.
I believe all iPhone models support two texture stages, so you should be able to combine two of your layers into a single draw call. You might still need to resort to blending for the third layer.
Also note that alpha testing could be faster than alpha blending.
Good luck!
The back nebula should definitely be opaque; everything else is getting drawn on top of it, and I assume the only thing behind it is black. Also, prideout has a point: assuming your star layers can have effectively 1-bit alpha, that's definitely something you can try. Failing that, the GL_POINTS technique Harald mentions would work as well.

How do I use CALayer with the iPhone?

Currently, I have a UIView subclass that "stamps" a single 2px by 2px CGLayerRef across the screen, up to 160 x 240 times.
I currently animate this by moving the UIView "up" the screen 2 pixels (actually, a UIImageView) and then drawing the next "row".
Would using multiple CALayer layers speed up performance of rendering this animation?
Are there tutorials, sample applications or code snippets for use of CALayer with the iPhone SDK?
The reason I ask is that most of the code snippets I find that demonstrate simple examples of CALayer employ method calls that do not work with the iPhone SDK. I appreciate any advice or pointers.
Okay, well, if you want something that has some good examples of CA good that draws things like that and works on the phone, I recommend the GeekGameBoard code that Jens Aflke published (it is an improved version of some Apple demo code).
Based on what you are describing I think you are doing somthing way more complicated than it needs be. My impression is you want basically a static view that you are animating by shifting its position so that it is partially off screen. If you just need to set some static content in your drawRect going through layers is not going to be faster than just calling CGFillRect() with your color. After that you could just use implicit animations and the animator proxy on UIView to move the view. I suspect you could even get rid of the custom drawRect: implementation with a patterned UIColor, but I honestly have not benchmarked the difference between the two.
What CALayer methods are you seeing that don't work on iPhone? Aside from animation features tied to CoreImage I have not noticed much that is missing. The big thing you are likely to notice is that all views are layer backed (so you do not need to do anything special to use layers, you can just grab a UIView's layer through the layer accessors methos), and the coordinate system has a top left origin.
In any event, generally having more things is slower than having fewer things. If you are just repeating the same pattern over and over again you are likely to find the best performance is implementing a custom UIView/CALayer/UIColor that knows how to draw what you want, rather than placing visually identical layers or views next to each other.
Having said that, generally layers are lighter weight than views, so if you have a lot of separate elements that you need to keep logically separated you will find that moving to layers can be a win over using views.
You might want to look at -[UIColor initWithPatternImage:] depending on exactly what you are trying to do. If you are using this two pixel pattern as a background color you could just make a UIColor that draws it and set the background.
What CALayer methods are you seeing that don't work on iPhone?
As one example, I tried implementing the grid demo here, without much luck. It looks like CAConstraintLayoutManager and CAConstraint are not available in QuartzCore.h.
In another attempt, I tried a very simple, small 20x20 CALayer object as a sublayer of my UIView's layer property, but that didn't show up.
Right now, I have a custom UIView of which I override the drawRect method. In drawRect I grab a context and render two types of CGLayerRefs:
At "off" cells I draw the background color across the entire 320x480 canvas.
At "on" cells, I either draw a single CGLayerRef across a grid of 320x480 pixels (initialization) or across a 320x2 row (animation).
During animation, I make a UIImageView clip view from 320x478 pixels, and draw a single row. This "pushes" my bitmap up the screen two pixels at a time.
Basically, I'd like to test whether or not using CALayer will accomplish two things:
Make my rendering faster, if CALayer has less overhead than what I'm doing now
Make my animation smoother, by letting me transition a layer up the screen smoothly
Unfortunately, I can't seem to get a basic CALayer working at the moment, and haven't found a good chunk of sample code to look at and play with.