Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(828)

Side by Side Diff: talk/app/webrtc/objc/RTCEAGLVideoView.m

Issue 1347013002: RTCEAGLVideoView: Fix GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT error. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Fix comment: 80 chars per line Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « AUTHORS ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * libjingle 2 * libjingle
3 * Copyright 2014 Google Inc. 3 * Copyright 2014 Google Inc.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * 7 *
8 * 1. Redistributions of source code must retain the above copyright notice, 8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer. 9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice, 10 * 2. Redistributions in binary form must reproduce the above copyright notice,
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 - (void)invalidate { 85 - (void)invalidate {
86 [_displayLink invalidate]; 86 [_displayLink invalidate];
87 } 87 }
88 88
89 - (void)displayLinkDidFire:(CADisplayLink*)displayLink { 89 - (void)displayLinkDidFire:(CADisplayLink*)displayLink {
90 _timerHandler(); 90 _timerHandler();
91 } 91 }
92 92
93 @end 93 @end
94 94
95 // RTCEAGLVideoView wraps a GLKView which is setup with
96 // enableSetNeedsDisplay = NO for the purpose of gaining control of
97 // exactly when to call -[GLKView display]. This need for extra
98 // control is required to avoid triggering method calls on GLKView
99 // that results in attempting to bind the underlying render buffer
100 // when the drawable size would be empty which would result in the
101 // error GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT. -[GLKView display] is
102 // the method that will trigger the binding of the render
103 // buffer. Because the standard behaviour of -[UIView setNeedsDisplay]
104 // is disabled for the reasons above, the RTCEAGLVideoView maintains
105 // its own |isDirty| flag.
106
95 @interface RTCEAGLVideoView () <GLKViewDelegate> 107 @interface RTCEAGLVideoView () <GLKViewDelegate>
96 // |i420Frame| is set when we receive a frame from a worker thread and is read 108 // |i420Frame| is set when we receive a frame from a worker thread and is read
97 // from the display link callback so atomicity is required. 109 // from the display link callback so atomicity is required.
98 @property(atomic, strong) RTCI420Frame* i420Frame; 110 @property(atomic, strong) RTCI420Frame* i420Frame;
99 @property(nonatomic, readonly) GLKView* glkView; 111 @property(nonatomic, readonly) GLKView* glkView;
100 @property(nonatomic, readonly) RTCOpenGLVideoRenderer* glRenderer; 112 @property(nonatomic, readonly) RTCOpenGLVideoRenderer* glRenderer;
101 @end 113 @end
102 114
103 @implementation RTCEAGLVideoView { 115 @implementation RTCEAGLVideoView {
104 RTCDisplayLinkTimer* _timer; 116 RTCDisplayLinkTimer* _timer;
105 GLKView* _glkView; 117 GLKView* _glkView;
106 RTCOpenGLVideoRenderer* _glRenderer; 118 RTCOpenGLVideoRenderer* _glRenderer;
119 // This flag should only be set and read on the main thread (e.g. by
120 // setNeedsDisplay)
121 BOOL _isDirty;
107 } 122 }
108 123
109 - (instancetype)initWithFrame:(CGRect)frame { 124 - (instancetype)initWithFrame:(CGRect)frame {
110 if (self = [super initWithFrame:frame]) { 125 if (self = [super initWithFrame:frame]) {
111 [self configure]; 126 [self configure];
112 } 127 }
113 return self; 128 return self;
114 } 129 }
115 130
116 - (instancetype)initWithCoder:(NSCoder *)aDecoder { 131 - (instancetype)initWithCoder:(NSCoder *)aDecoder {
(...skipping 13 matching lines...) Expand all
130 145
131 // GLKView manages a framebuffer for us. 146 // GLKView manages a framebuffer for us.
132 _glkView = [[GLKView alloc] initWithFrame:CGRectZero 147 _glkView = [[GLKView alloc] initWithFrame:CGRectZero
133 context:glContext]; 148 context:glContext];
134 _glkView.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888; 149 _glkView.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
135 _glkView.drawableDepthFormat = GLKViewDrawableDepthFormatNone; 150 _glkView.drawableDepthFormat = GLKViewDrawableDepthFormatNone;
136 _glkView.drawableStencilFormat = GLKViewDrawableStencilFormatNone; 151 _glkView.drawableStencilFormat = GLKViewDrawableStencilFormatNone;
137 _glkView.drawableMultisample = GLKViewDrawableMultisampleNone; 152 _glkView.drawableMultisample = GLKViewDrawableMultisampleNone;
138 _glkView.delegate = self; 153 _glkView.delegate = self;
139 _glkView.layer.masksToBounds = YES; 154 _glkView.layer.masksToBounds = YES;
155 _glkView.enableSetNeedsDisplay = NO;
140 [self addSubview:_glkView]; 156 [self addSubview:_glkView];
141 157
142 // Listen to application state in order to clean up OpenGL before app goes 158 // Listen to application state in order to clean up OpenGL before app goes
143 // away. 159 // away.
144 NSNotificationCenter* notificationCenter = 160 NSNotificationCenter* notificationCenter =
145 [NSNotificationCenter defaultCenter]; 161 [NSNotificationCenter defaultCenter];
146 [notificationCenter addObserver:self 162 [notificationCenter addObserver:self
147 selector:@selector(willResignActive) 163 selector:@selector(willResignActive)
148 name:UIApplicationWillResignActiveNotification 164 name:UIApplicationWillResignActiveNotification
149 object:nil]; 165 object:nil];
150 [notificationCenter addObserver:self 166 [notificationCenter addObserver:self
151 selector:@selector(didBecomeActive) 167 selector:@selector(didBecomeActive)
152 name:UIApplicationDidBecomeActiveNotification 168 name:UIApplicationDidBecomeActiveNotification
153 object:nil]; 169 object:nil];
154 170
155 // Frames are received on a separate thread, so we poll for current frame 171 // Frames are received on a separate thread, so we poll for current frame
156 // using a refresh rate proportional to screen refresh frequency. This 172 // using a refresh rate proportional to screen refresh frequency. This
157 // occurs on the main thread. 173 // occurs on the main thread.
158 __weak RTCEAGLVideoView* weakSelf = self; 174 __weak RTCEAGLVideoView* weakSelf = self;
159 _timer = [[RTCDisplayLinkTimer alloc] initWithTimerHandler:^{ 175 _timer = [[RTCDisplayLinkTimer alloc] initWithTimerHandler:^{
160 RTCEAGLVideoView* strongSelf = weakSelf; 176 RTCEAGLVideoView* strongSelf = weakSelf;
161 // Don't render if frame hasn't changed. 177 [strongSelf displayLinkTimerDidFire];
162 if (strongSelf.glRenderer.lastDrawnFrame == strongSelf.i420Frame) {
163 return;
164 }
165 // This tells the GLKView that it's dirty, which will then call the
166 // GLKViewDelegate method implemented below.
167 [strongSelf.glkView setNeedsDisplay];
168 }]; 178 }];
169 [self setupGL]; 179 [self setupGL];
170 } 180 }
171 181
172 - (void)dealloc { 182 - (void)dealloc {
173 [[NSNotificationCenter defaultCenter] removeObserver:self]; 183 [[NSNotificationCenter defaultCenter] removeObserver:self];
174 UIApplicationState appState = 184 UIApplicationState appState =
175 [UIApplication sharedApplication].applicationState; 185 [UIApplication sharedApplication].applicationState;
176 if (appState == UIApplicationStateActive) { 186 if (appState == UIApplicationStateActive) {
177 [self teardownGL]; 187 [self teardownGL];
178 } 188 }
179 [_timer invalidate]; 189 [_timer invalidate];
180 } 190 }
181 191
182 #pragma mark - UIView 192 #pragma mark - UIView
183 193
194 - (void)setNeedsDisplay {
195 [super setNeedsDisplay];
196 _isDirty = YES;
197 }
198
199 - (void)setNeedsDisplayInRect:(CGRect)rect {
200 [super setNeedsDisplayInRect:rect];
201 _isDirty = YES;
202 }
203
184 - (void)layoutSubviews { 204 - (void)layoutSubviews {
185 [super layoutSubviews]; 205 [super layoutSubviews];
186 _glkView.frame = self.bounds; 206 _glkView.frame = self.bounds;
187 } 207 }
188 208
189 #pragma mark - GLKViewDelegate 209 #pragma mark - GLKViewDelegate
190 210
191 // This method is called when the GLKView's content is dirty and needs to be 211 // This method is called when the GLKView's content is dirty and needs to be
192 // redrawn. This occurs on main thread. 212 // redrawn. This occurs on main thread.
193 - (void)glkView:(GLKView*)view drawInRect:(CGRect)rect { 213 - (void)glkView:(GLKView*)view drawInRect:(CGRect)rect {
(...skipping 12 matching lines...) Expand all
206 [strongSelf.delegate videoView:strongSelf didChangeVideoSize:size]; 226 [strongSelf.delegate videoView:strongSelf didChangeVideoSize:size];
207 }); 227 });
208 } 228 }
209 229
210 - (void)renderFrame:(RTCI420Frame*)frame { 230 - (void)renderFrame:(RTCI420Frame*)frame {
211 self.i420Frame = frame; 231 self.i420Frame = frame;
212 } 232 }
213 233
214 #pragma mark - Private 234 #pragma mark - Private
215 235
236 - (void)displayLinkTimerDidFire {
237 // Don't render unless video frame have changed or the view content
238 // has explicitly been marked dirty.
239 if (!_isDirty && _glRenderer.lastDrawnFrame == self.i420Frame) {
240 return;
241 }
242
243 // Always reset isDirty at this point, even if -[GLKView display]
244 // won't be called in the case the drawable size is empty.
245 _isDirty = NO;
246
247 // Only call -[GLKView display] if the drawable size is
248 // non-empty. Calling display will make the GLKView setup its
249 // render buffer if necessary, but that will fail with error
250 // GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT if size is empty.
251 if (self.bounds.size.width > 0 && self.bounds.size.height > 0) {
252 [_glkView display];
253 }
254 }
255
216 - (void)setupGL { 256 - (void)setupGL {
217 self.i420Frame = nil; 257 self.i420Frame = nil;
218 [_glRenderer setupGL]; 258 [_glRenderer setupGL];
219 _timer.isPaused = NO; 259 _timer.isPaused = NO;
220 } 260 }
221 261
222 - (void)teardownGL { 262 - (void)teardownGL {
223 self.i420Frame = nil; 263 self.i420Frame = nil;
224 _timer.isPaused = YES; 264 _timer.isPaused = YES;
225 [_glkView deleteDrawable]; 265 [_glkView deleteDrawable];
226 [_glRenderer teardownGL]; 266 [_glRenderer teardownGL];
227 } 267 }
228 268
229 - (void)didBecomeActive { 269 - (void)didBecomeActive {
230 [self setupGL]; 270 [self setupGL];
231 } 271 }
232 272
233 - (void)willResignActive { 273 - (void)willResignActive {
234 [self teardownGL]; 274 [self teardownGL];
235 } 275 }
236 276
237 @end 277 @end
OLDNEW
« no previous file with comments | « AUTHORS ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698