开发者

EAGLView to UIImage timing question

开发者 https://www.devze.com 2023-03-28 00:58 出处:网络
I have a EAGLView that I wish to convert into a UIImage. I can do this with the solution posted here:

I have a EAGLView that I wish to convert into a UIImage. I can do this with the solution posted here:

How to get UIImage from EAGLVie开发者_运维问答w?

However, I can only accomplish this if a small amount of time has gone by between the creation of the EAGLView and the UIImage.

This code, which creates a EAGLView, and then a UIImageView right afterwards, does not work:

EAGLView *EAGLphoto = [[EAGLView alloc] initWithImage:photo.workAreaImage];

[theWorkArea.photoArea1 addSubview:EAGLphoto];

//I put a glfinish() here but it didn't help

UIImageView *photoView = [[UIImageView alloc] initWithImage:[self glToUIImage]];
//glToUIImage is taken from the link above

[theWorkArea.photoArea2 addSubview:photoView];

I'm assuming the UIImageView tries to get created before the EAGLView is finished being created. I tried to put a glfinish() in between but it did nothing. When I run the code, the EAGLView shows up fine but the UIImageView shows up as black.

However, this modified version of the above code works:

EAGLView *EAGLphoto = [[EAGLView alloc] initWithImage:photo.workAreaImage];

[theWorkArea.photoArea1 addSubview:EAGLphoto];

[self performSelector:@selector(getUIImage) withObject:nil afterDelay:0.1];

- (void)getUIImage {

    UIImageView *photoView = [[UIImageView alloc] initWithImage:[self glToUIImage]];
    //glToUIImage is taken from the link above

    [theWorkArea.photoArea2 addSubview:photoView];

}

Am I using glfinish() incorrectly? Is there a better method than my hack?


Usually when you make visible changes to UIKit objects instead of updating instantly they merely flag themselves to make those changes in the future, then do the whole set of changes as a batch next time you relinquish the main thread (by returning to the runloop). That's not a misfeature or a failure in the implementation, it's actually usually what you implicitly expect, being the reason you can write code like:

view.frame = someNewFrame;
view.someOtherProperty = someOtherValue;

And not worry that every so often the view will visibly adopt the new frame before adopting the other changes. As a rule, you want the things you do to views to appear to be atomic.

Occasionally you run into a situation, as you have here, where the fact that changes you've already requested haven't come into effect yet is exposed. frame and someOtherProperty would return their new values in the above example so that you don't care whether the changes took effect immediately or not, but based on your observation about performSelector:withObject:afterDelay: it seems likely that you've stumbled upon a situation where the change doesn't pretend to be immediate.

EAGLView is difficult to diagnose because it's not really a UIKit feature. The CAEAGLLayer that it's built upon is, but EAGLView is just the name Apple have adopted for a custom UIView subclass built on CAEAGLLayer in various example projects. They've not been consistent about the interface or implementation of EAGLView across their examples, but at a guess I'd say that probably it's creating the OpenGL frame buffer object (that is, the thing that OpenGL uses to store numbers related to pixels, allowing glReadPixels to work) only when asked to lay itself out, and it doesn't lay itself out until UIKit asks it to do so. Which isn't until you've dropped out to the runloop.

That diagnosis can be confirmed by checking the code of the EAGLView that you have. If there are a bunch of calls to things like glGenFramebuffers that are triggered as a result of layoutSubviews, drawRect or some other method that isn't called directly by the relevant init then that proves it.

Assuming that diagnosis to be correct, you could adapt EAGLView but I think probably the best solution is just to stick to performSelector:withObject:afterDelay:0. This isn't a race condition, so that solution isn't in the slightest bit flakey or unreliable, it's just a slightly roundabout way of saying "let UIKit catch up with all of those instructions, given that I know that'll let EAGLView get into a meaningful state, then continue with my stuff".

0

精彩评论

暂无评论...
验证码 换一张
取 消