CARenderer never launches

I have been trying for hours to display the Core Animation layer tree in an OpenGL context using CARenderer. Currently, the OpenGL context is provided by the NSOpenGLView subclass set in Interface Builder, with default settings.

This is how I installed CALayers in my example:

l1 = [[CALayer layer] retain]; // l1 is an instance variable l1.bounds = CGRectMake(0, 0, 100, 100); l1.backgroundColor = CGColorCreateGenericRGB(1, 1, 0, 1); CALayer* l2 = [CALayer layer]; l2.bounds = CGRectMake(0, 0, 20, 20); l2.backgroundColor = CGColorCreateGenericRGB(1, 0, 0, 1); l2.position = CGPointMake(50, 50); [l1 addSublayer:l2]; 

If I add them to a regular NSView, they will display just fine.

Here is the drawing code from my subclass NSOpenGLView:

 - (void) drawRect:(NSRect)dirtyRect { NSRect frame = [self frame]; // set up context according to CARenderer.h instructions glViewport(0, 0, frame.size.width, frame.size.height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, frame.size.width, 0, frame.size.height, -1, 1); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); if (l1) { CARenderer* renderer = [CARenderer rendererWithCGLContext:[[self openGLContext] CGLContextObj] options:nil]; renderer.layer = l1; renderer.bounds = NSRectToCGRect(frame); [renderer beginFrameAtTime:0.0 timeStamp:NULL]; [renderer addUpdateRect:renderer.bounds]; [renderer render]; [renderer endFrame]; } glFlush(); } 

I confirmed that the view is redrawn after the layers were created, and the view itself seems to work fine - the OpenGL commands that I issue are displayed correctly. CARenderer really comes to life (in fact, if l1 is already tied to a different context at the time this code is run, it will dutifully complain). There simply is no visible way out.

Other things I've tried: wrapping CARenderer code in CATransaction, messing around with NSOpenGLView settings in Interface Builder, passing the whole thing into a manually created OpenGL context and saving it in an image file ... all with the same effect: OpenGL's own commands show a fine CARenderer shows nothing.

I suspect that something is wrong with how my OpenGL context is set up, or that I could even somehow render outside of my viewport ... maybe some really silly little details. Unfortunately, both the documentation and sample code for CARenderer on the Internet are somewhat rare, and although I am fairly experienced with Core Animation, my knowledge of OpenGL is clearly limited.

So, right now, I'm seriously at a dead end and completely out of ideas, so any pointers are really appreciated!

Greetings

+4
source share
1 answer

Oh wow. Therefore, if someone is interested, I got it โ€œmostly workingโ€ in the meantime. Here is the relevant code:

 - (void) drawRect:(NSRect)dirtyRect { NSRect viewBounds = [self bounds]; // set up context according to CARenderer.h instructions glViewport(0, 0, viewBounds.size.width, viewBounds.size.height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, viewBounds.size.width, 0, viewBounds.size.height, -1, 1); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); [renderer beginFrameAtTime:0.0 timeStamp:NULL]; [renderer addUpdateRect:renderer.bounds]; [renderer render]; [renderer endFrame]; glFlush(); } - (void) prepareOpenGL { renderer = [[CARenderer rendererWithCGLContext:[[self openGLContext] CGLContextObj] options:nil] retain]; [CATransaction begin]; CALayer* l = [CALayer layer]; l.bounds = CGRectMake(0, 0, 100, 100); l.backgroundColor = CGColorCreateGenericRGB(1, 1, 0, 1); renderer.layer = l; renderer.bounds = l.bounds; [CATransaction commit]; } 

Notice the CATransaction block around the layer / render code. Without this, the layer will not be displayed at all (like my original problem) or will be displayed only after a short delay, i.e. When the view will be redrawn after a while. As to why this is necessary, I am still not sure, and I would be more than happy if someone could enlighten me on this issue.

Obviously, this solution may still be in some way erroneous, but I decided to leave it here, currently considering the lack of sample code for CARenderer .

EDIT: As I found out later, one rather unobvious error with the solution above is that 0.0 is passed to the beginFrameAtTime method beginFrameAtTime ; instead, it should be a value from CACurrentMediaTime . This eliminates the need for CATransaction blocks, and also fixes some other errors along the way. Just like heads-up for anyone who might stumble upon this answer.

+4
source

All Articles