From ac7d97fea6a6781ad3a77c8653e62ea9ec1f188c Mon Sep 17 00:00:00 2001 From: Zeke Chin Date: Mon, 20 Apr 2015 14:33:25 -0700 Subject: [PATCH] Remove frame copy in RTCOpenGLVideoRenderer. BUG=1128 R=magjed@webrtc.org Review URL: https://webrtc-codereview.appspot.com/44039004 Cr-Commit-Position: refs/heads/master@{#9036} --- talk/app/webrtc/objc/RTCEAGLVideoView.m | 5 +- .../app/webrtc/objc/RTCOpenGLVideoRenderer.mm | 155 +++++++++--------- 2 files changed, 84 insertions(+), 76 deletions(-) diff --git a/talk/app/webrtc/objc/RTCEAGLVideoView.m b/talk/app/webrtc/objc/RTCEAGLVideoView.m index 9b089da883..61040ba102 100644 --- a/talk/app/webrtc/objc/RTCEAGLVideoView.m +++ b/talk/app/webrtc/objc/RTCEAGLVideoView.m @@ -122,7 +122,10 @@ - (void)configure { EAGLContext* glContext = - [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; + if (!glContext) { + glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + } _glRenderer = [[RTCOpenGLVideoRenderer alloc] initWithContext:glContext]; // GLKView manages a framebuffer for us. diff --git a/talk/app/webrtc/objc/RTCOpenGLVideoRenderer.mm b/talk/app/webrtc/objc/RTCOpenGLVideoRenderer.mm index 447a0a7e46..cfead91bca 100644 --- a/talk/app/webrtc/objc/RTCOpenGLVideoRenderer.mm +++ b/talk/app/webrtc/objc/RTCOpenGLVideoRenderer.mm @@ -36,7 +36,7 @@ #include "webrtc/base/scoped_ptr.h" #if TARGET_OS_IPHONE -#import +#import #else #import #endif @@ -66,17 +66,6 @@ #define FRAGMENT_SHADER_TEXTURE "texture" #endif -void CopyPlane(uint8_t* dst, - int dst_stride, - const uint8_t* src, - int src_stride, - int width, - int height) { - for (int y = 0; y < height; ++y) { - memcpy(dst + y * dst_stride, src + y * src_stride, width); - } -} - // Vertex shader doesn't do anything except pass coordinates through. static const char kVertexShaderSource[] = SHADER_VERSION @@ -193,6 +182,9 @@ static const GLsizei kNumTextures = 3 * kNumTextureSets; GLint _ySampler; GLint _uSampler; GLint _vSampler; + // Used to create a non-padded plane for GPU upload when we receive padded + // frames. + rtc::scoped_ptr _planeBuffer; } + (void)initialize { @@ -376,78 +368,91 @@ static const GLsizei kNumTextures = 3 * kNumTextureSets; GL_UNSIGNED_BYTE, 0); } + if (frame.yPitch != frame.width || frame.uPitch != frame.chromaWidth || + frame.vPitch != frame.chromaWidth) { + _planeBuffer.reset(new uint8_t[frame.width * frame.height]); + } else { + _planeBuffer.reset(); + } return YES; } +- (void)uploadPlane:(const uint8_t*)plane + sampler:(GLint)sampler + offset:(NSUInteger)offset + width:(NSUInteger)width + height:(NSUInteger)height + stride:(NSInteger)stride { + glActiveTexture(GL_TEXTURE0 + offset); + // When setting texture sampler uniforms, the texture index is used not + // the texture handle. + glUniform1i(sampler, offset); +#if TARGET_OS_IPHONE + BOOL hasUnpackRowLength = _context.API == kEAGLRenderingAPIOpenGLES3; +#else + BOOL hasUnpackRowLength = YES; +#endif + const uint8_t* uploadPlane = plane; + if (stride != width) { + if (hasUnpackRowLength) { + // GLES3 allows us to specify stride. + glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); + glTexImage2D(GL_TEXTURE_2D, + 0, + RTC_PIXEL_FORMAT, + width, + height, + 0, + RTC_PIXEL_FORMAT, + GL_UNSIGNED_BYTE, + uploadPlane); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + return; + } else { + // Make an unpadded copy and upload that instead. Quick profiling showed + // that this is faster than uploading row by row using glTexSubImage2D. + uint8_t* unpaddedPlane = _planeBuffer.get(); + for (NSUInteger y = 0; y < height; ++y) { + memcpy(unpaddedPlane + y * width, plane + y * stride, width); + } + uploadPlane = unpaddedPlane; + } + } + glTexImage2D(GL_TEXTURE_2D, + 0, + RTC_PIXEL_FORMAT, + width, + height, + 0, + RTC_PIXEL_FORMAT, + GL_UNSIGNED_BYTE, + uploadPlane); +} + - (BOOL)updateTextureDataForFrame:(RTCI420Frame*)frame { NSUInteger textureOffset = _currentTextureSet * 3; NSAssert(textureOffset + 3 <= kNumTextures, @"invalid offset"); - // TODO(magjed): Remove this frame copy, BUG=1128. - rtc::scoped_ptr tmp; - if (frame.yPitch != frame.width || frame.uPitch != frame.chromaWidth || - frame.vPitch != frame.chromaWidth) { - tmp.reset(new uint8_t[frame.width * frame.height]); - } + [self uploadPlane:frame.yPlane + sampler:_ySampler + offset:textureOffset + width:frame.width + height:frame.height + stride:frame.yPitch]; - const uint8_t* yPlane = frame.yPlane; - if (frame.yPitch != frame.width) { - yPlane = tmp.get(); - CopyPlane(tmp.get(), frame.width, frame.yPlane, frame.yPitch, frame.width, - frame.height); - } + [self uploadPlane:frame.uPlane + sampler:_uSampler + offset:textureOffset + 1 + width:frame.chromaWidth + height:frame.chromaHeight + stride:frame.uPitch]; - glActiveTexture(GL_TEXTURE0 + textureOffset); - // When setting texture sampler uniforms, the texture index is used not - // the texture handle. - glUniform1i(_ySampler, textureOffset); - glTexImage2D(GL_TEXTURE_2D, - 0, - RTC_PIXEL_FORMAT, - frame.width, - frame.height, - 0, - RTC_PIXEL_FORMAT, - GL_UNSIGNED_BYTE, - yPlane); - - const uint8_t* uPlane = frame.uPlane; - if (frame.uPitch != frame.chromaWidth) { - uPlane = tmp.get(); - CopyPlane(tmp.get(), frame.chromaWidth, frame.uPlane, frame.uPitch, - frame.chromaWidth, frame.chromaHeight); - } - - glActiveTexture(GL_TEXTURE0 + textureOffset + 1); - glUniform1i(_uSampler, textureOffset + 1); - glTexImage2D(GL_TEXTURE_2D, - 0, - RTC_PIXEL_FORMAT, - frame.chromaWidth, - frame.chromaHeight, - 0, - RTC_PIXEL_FORMAT, - GL_UNSIGNED_BYTE, - uPlane); - - const uint8_t* vPlane = frame.vPlane; - if (frame.vPitch != frame.chromaWidth) { - vPlane = tmp.get(); - CopyPlane(tmp.get(), frame.chromaWidth, frame.vPlane, frame.vPitch, - frame.chromaWidth, frame.chromaHeight); - } - - glActiveTexture(GL_TEXTURE0 + textureOffset + 2); - glUniform1i(_vSampler, textureOffset + 2); - glTexImage2D(GL_TEXTURE_2D, - 0, - RTC_PIXEL_FORMAT, - frame.chromaWidth, - frame.chromaHeight, - 0, - RTC_PIXEL_FORMAT, - GL_UNSIGNED_BYTE, - vPlane); + [self uploadPlane:frame.vPlane + sampler:_vSampler + offset:textureOffset + 2 + width:frame.chromaWidth + height:frame.chromaHeight + stride:frame.vPitch]; _currentTextureSet = (_currentTextureSet + 1) % kNumTextureSets; return YES;