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

Side by Side Diff: webrtc/sdk/objc/Framework/Classes/RTCI420Shader.mm

Issue 2842453002: ObjC: Split out I420 texture uploading into separate class (Closed)
Patch Set: Make uploadFrameToTextures return void Created 3 years, 7 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 | « webrtc/sdk/BUILD.gn ('k') | webrtc/sdk/objc/Framework/Classes/RTCI420TextureCache.h » ('j') | 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 * Copyright 2016 The WebRTC project authors. All Rights Reserved. 2 * Copyright 2016 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source 5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #import "RTCShader.h" 11 #import "RTCShader.h"
12 12
13 #include <vector> 13 #import "RTCI420TextureCache.h"
14
15 #import "RTCShader+Private.h" 14 #import "RTCShader+Private.h"
16 #import "WebRTC/RTCLogging.h" 15 #import "WebRTC/RTCLogging.h"
17 #import "WebRTC/RTCVideoFrame.h" 16 #import "WebRTC/RTCVideoFrame.h"
18 17
19 #include "webrtc/base/optional.h" 18 #include "webrtc/base/optional.h"
20 19
21 // |kNumTextures| must not exceed 8, which is the limit in OpenGLES2. Two sets
22 // of 3 textures are used here, one for each of the Y, U and V planes. Having
23 // two sets alleviates CPU blockage in the event that the GPU is asked to render
24 // to a texture that is already in use.
25 static const GLsizei kNumTextureSets = 2;
26 static const GLsizei kNumTexturesPerSet = 3;
27 static const GLsizei kNumTextures = kNumTexturesPerSet * kNumTextureSets;
28
29 // Fragment shader converts YUV values from input textures into a final RGB 20 // Fragment shader converts YUV values from input textures into a final RGB
30 // pixel. The conversion formula is from http://www.fourcc.org/fccyvrgb.php. 21 // pixel. The conversion formula is from http://www.fourcc.org/fccyvrgb.php.
31 static const char kI420FragmentShaderSource[] = 22 static const char kI420FragmentShaderSource[] =
32 SHADER_VERSION 23 SHADER_VERSION
33 "precision highp float;" 24 "precision highp float;"
34 FRAGMENT_SHADER_IN " vec2 v_texcoord;\n" 25 FRAGMENT_SHADER_IN " vec2 v_texcoord;\n"
35 "uniform lowp sampler2D s_textureY;\n" 26 "uniform lowp sampler2D s_textureY;\n"
36 "uniform lowp sampler2D s_textureU;\n" 27 "uniform lowp sampler2D s_textureU;\n"
37 "uniform lowp sampler2D s_textureV;\n" 28 "uniform lowp sampler2D s_textureV;\n"
38 FRAGMENT_SHADER_OUT 29 FRAGMENT_SHADER_OUT
39 "void main() {\n" 30 "void main() {\n"
40 " float y, u, v, r, g, b;\n" 31 " float y, u, v, r, g, b;\n"
41 " y = " FRAGMENT_SHADER_TEXTURE "(s_textureY, v_texcoord).r;\n" 32 " y = " FRAGMENT_SHADER_TEXTURE "(s_textureY, v_texcoord).r;\n"
42 " u = " FRAGMENT_SHADER_TEXTURE "(s_textureU, v_texcoord).r;\n" 33 " u = " FRAGMENT_SHADER_TEXTURE "(s_textureU, v_texcoord).r;\n"
43 " v = " FRAGMENT_SHADER_TEXTURE "(s_textureV, v_texcoord).r;\n" 34 " v = " FRAGMENT_SHADER_TEXTURE "(s_textureV, v_texcoord).r;\n"
44 " u = u - 0.5;\n" 35 " u = u - 0.5;\n"
45 " v = v - 0.5;\n" 36 " v = v - 0.5;\n"
46 " r = y + 1.403 * v;\n" 37 " r = y + 1.403 * v;\n"
47 " g = y - 0.344 * u - 0.714 * v;\n" 38 " g = y - 0.344 * u - 0.714 * v;\n"
48 " b = y + 1.770 * u;\n" 39 " b = y + 1.770 * u;\n"
49 " " FRAGMENT_SHADER_COLOR " = vec4(r, g, b, 1.0);\n" 40 " " FRAGMENT_SHADER_COLOR " = vec4(r, g, b, 1.0);\n"
50 " }\n"; 41 " }\n";
51 42
52 @implementation RTCI420Shader { 43 @implementation RTCI420Shader {
53 BOOL _hasUnpackRowLength; 44 RTCI420TextureCache* textureCache;
54 GLint _currentTextureSet;
55 // Handles for OpenGL constructs. 45 // Handles for OpenGL constructs.
56 GLuint _textures[kNumTextures];
57 GLuint _i420Program; 46 GLuint _i420Program;
58 GLuint _vertexArray; 47 GLuint _vertexArray;
59 GLuint _vertexBuffer; 48 GLuint _vertexBuffer;
60 GLint _ySampler; 49 GLint _ySampler;
61 GLint _uSampler; 50 GLint _uSampler;
62 GLint _vSampler; 51 GLint _vSampler;
63 // Store current rotation and only upload new vertex data when rotation 52 // Store current rotation and only upload new vertex data when rotation
64 // changes. 53 // changes.
65 rtc::Optional<RTCVideoRotation> _currentRotation; 54 rtc::Optional<RTCVideoRotation> _currentRotation;
66 // Used to create a non-padded plane for GPU upload when we receive padded
67 // frames.
68 std::vector<uint8_t> _planeBuffer;
69 } 55 }
70 56
71 - (instancetype)initWithContext:(GlContextType *)context { 57 - (instancetype)initWithContext:(GlContextType *)context {
72 if (self = [super init]) { 58 if (self = [super init]) {
73 #if TARGET_OS_IPHONE 59 textureCache = [[RTCI420TextureCache alloc] initWithContext:context];
74 _hasUnpackRowLength = (context.API == kEAGLRenderingAPIOpenGLES3);
75 #else
76 _hasUnpackRowLength = YES;
77 #endif
78 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 60 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
79 if (![self setupI420Program] || ![self setupTextures] || 61 if (![self setupI420Program] ||
80 !RTCSetupVerticesForProgram(_i420Program, &_vertexBuffer, &_vertexArray) ) { 62 !RTCSetupVerticesForProgram(_i420Program, &_vertexBuffer, &_vertexArray) ) {
81 RTCLog(@"Failed to initialize RTCI420Shader."); 63 RTCLog(@"Failed to initialize RTCI420Shader.");
82 self = nil; 64 self = nil;
83 } 65 }
84 } 66 }
85 return self; 67 return self;
86 } 68 }
87 69
88 - (void)dealloc { 70 - (void)dealloc {
89 glDeleteProgram(_i420Program); 71 glDeleteProgram(_i420Program);
90 glDeleteTextures(kNumTextures, _textures);
91 glDeleteBuffers(1, &_vertexBuffer); 72 glDeleteBuffers(1, &_vertexBuffer);
92 glDeleteVertexArrays(1, &_vertexArray); 73 glDeleteVertexArrays(1, &_vertexArray);
93 } 74 }
94 75
95 - (BOOL)setupI420Program { 76 - (BOOL)setupI420Program {
96 _i420Program = RTCCreateProgramFromFragmentSource(kI420FragmentShaderSource); 77 _i420Program = RTCCreateProgramFromFragmentSource(kI420FragmentShaderSource);
97 if (!_i420Program) { 78 if (!_i420Program) {
98 return NO; 79 return NO;
99 } 80 }
100 _ySampler = glGetUniformLocation(_i420Program, "s_textureY"); 81 _ySampler = glGetUniformLocation(_i420Program, "s_textureY");
101 _uSampler = glGetUniformLocation(_i420Program, "s_textureU"); 82 _uSampler = glGetUniformLocation(_i420Program, "s_textureU");
102 _vSampler = glGetUniformLocation(_i420Program, "s_textureV"); 83 _vSampler = glGetUniformLocation(_i420Program, "s_textureV");
103 84
104 return (_ySampler >= 0 && _uSampler >= 0 && _vSampler >= 0); 85 return (_ySampler >= 0 && _uSampler >= 0 && _vSampler >= 0);
105 } 86 }
106 87
107 - (BOOL)setupTextures {
108 glGenTextures(kNumTextures, _textures);
109 // Set parameters for each of the textures we created.
110 for (GLsizei i = 0; i < kNumTextures; i++) {
111 glBindTexture(GL_TEXTURE_2D, _textures[i]);
112 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
113 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
114 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
115 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
116 }
117 return YES;
118 }
119
120 - (BOOL)drawFrame:(RTCVideoFrame*)frame { 88 - (BOOL)drawFrame:(RTCVideoFrame*)frame {
121 glUseProgram(_i420Program); 89 glUseProgram(_i420Program);
122 if (![self updateTextureDataForFrame:frame]) { 90
123 return NO; 91 [textureCache uploadFrameToTextures:frame];
124 } 92
125 #if !TARGET_OS_IPHONE 93 #if !TARGET_OS_IPHONE
126 glBindVertexArray(_vertexArray); 94 glBindVertexArray(_vertexArray);
127 #endif 95 #endif
96
97 glActiveTexture(GL_TEXTURE0);
98 glBindTexture(GL_TEXTURE_2D, textureCache.yTexture);
99 glUniform1i(_ySampler, 0);
100
101 glActiveTexture(GL_TEXTURE1);
102 glBindTexture(GL_TEXTURE_2D, textureCache.uTexture);
103 glUniform1i(_uSampler, 1);
104
105 glActiveTexture(GL_TEXTURE2);
106 glBindTexture(GL_TEXTURE_2D, textureCache.vTexture);
107 glUniform1i(_vSampler, 2);
108
128 glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); 109 glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
129 if (!_currentRotation || frame.rotation != *_currentRotation) { 110 if (!_currentRotation || frame.rotation != *_currentRotation) {
130 _currentRotation = rtc::Optional<RTCVideoRotation>(frame.rotation); 111 _currentRotation = rtc::Optional<RTCVideoRotation>(frame.rotation);
131 RTCSetVertexData(*_currentRotation); 112 RTCSetVertexData(*_currentRotation);
132 } 113 }
133 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 114 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
134 115
135 return YES; 116 return YES;
136 } 117 }
137 118
138 - (void)uploadPlane:(const uint8_t *)plane
139 sampler:(GLint)sampler
140 offset:(GLint)offset
141 width:(size_t)width
142 height:(size_t)height
143 stride:(int32_t)stride {
144 glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + offset));
145 glBindTexture(GL_TEXTURE_2D, _textures[offset]);
146
147 // When setting texture sampler uniforms, the texture index is used not
148 // the texture handle.
149 glUniform1i(sampler, offset);
150 const uint8_t *uploadPlane = plane;
151 if ((size_t)stride != width) {
152 if (_hasUnpackRowLength) {
153 // GLES3 allows us to specify stride.
154 glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
155 glTexImage2D(GL_TEXTURE_2D,
156 0,
157 RTC_PIXEL_FORMAT,
158 static_cast<GLsizei>(width),
159 static_cast<GLsizei>(height),
160 0,
161 RTC_PIXEL_FORMAT,
162 GL_UNSIGNED_BYTE,
163 uploadPlane);
164 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
165 return;
166 } else {
167 // Make an unpadded copy and upload that instead. Quick profiling showed
168 // that this is faster than uploading row by row using glTexSubImage2D.
169 uint8_t *unpaddedPlane = _planeBuffer.data();
170 for (size_t y = 0; y < height; ++y) {
171 memcpy(unpaddedPlane + y * width, plane + y * stride, width);
172 }
173 uploadPlane = unpaddedPlane;
174 }
175 }
176 glTexImage2D(GL_TEXTURE_2D,
177 0,
178 RTC_PIXEL_FORMAT,
179 static_cast<GLsizei>(width),
180 static_cast<GLsizei>(height),
181 0,
182 RTC_PIXEL_FORMAT,
183 GL_UNSIGNED_BYTE,
184 uploadPlane);
185 }
186
187 - (BOOL)updateTextureDataForFrame:(RTCVideoFrame *)frame {
188 GLint textureOffset = _currentTextureSet * 3;
189 NSAssert(textureOffset + 3 <= kNumTextures, @"invalid offset");
190
191 const int chromaWidth = (frame.width + 1) / 2;
192 const int chromaHeight = (frame.height + 1) / 2;
193 if (frame.strideY != frame.width ||
194 frame.strideU != chromaWidth ||
195 frame.strideV != chromaWidth) {
196 _planeBuffer.resize(frame.width * frame.height);
197 }
198
199 [self uploadPlane:frame.dataY
200 sampler:_ySampler
201 offset:textureOffset
202 width:frame.width
203 height:frame.height
204 stride:frame.strideY];
205
206 [self uploadPlane:frame.dataU
207 sampler:_uSampler
208 offset:textureOffset + 1
209 width:chromaWidth
210 height:chromaHeight
211 stride:frame.strideU];
212
213 [self uploadPlane:frame.dataV
214 sampler:_vSampler
215 offset:textureOffset + 2
216 width:chromaWidth
217 height:chromaHeight
218 stride:frame.strideV];
219
220 _currentTextureSet = (_currentTextureSet + 1) % kNumTextureSets;
221 return YES;
222 }
223
224 @end 119 @end
OLDNEW
« no previous file with comments | « webrtc/sdk/BUILD.gn ('k') | webrtc/sdk/objc/Framework/Classes/RTCI420TextureCache.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698