Chromium Code Reviews

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

Issue 2651743007: Add metal view, shaders and renderer. (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
« no previous file with comments | « webrtc/sdk/BUILD.gn ('k') | webrtc/sdk/objc/Framework/Classes/metal/RTCMTLVideoView.m » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2016 The WebRTC project authors. All Rights Reserved.
3 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #import "WebRTC/RTCMTLRenderer.h"
12
13 #import <Metal/Metal.h>
14 #import <MetalKit/MetalKit.h>
15
16 #import "WebRTC/RTCLogging.h"
17
18 float cubeVertexData[64] =
kthelgason 2017/01/24 14:17:59 static const
daniela-webrtc 2017/01/25 08:46:19 Done.
19 {
20 -1.0, -1.0, 0.0, 1.0,
21 1.0, -1.0, 1.0, 1.0,
22 -1.0, 1.0, 0.0, 0.0,
23 1.0, 1.0, 1.0, 0.0,
24
25 // rotation = 90, offset = 16.
26 -1.0, -1.0, 1.0, 1.0,
27 1.0, -1.0, 1.0, 0.0,
28 -1.0, 1.0, 0.0, 1.0,
29 1.0, 1.0, 0.0, 0.0,
30
31 // rotation = 180, offset = 32.
32 -1.0, -1.0, 1.0, 0.0,
33 1.0, -1.0, 0.0, 0.0,
34 -1.0, 1.0, 1.0, 1.0,
35 1.0, 1.0, 0.0, 1.0,
36
37 // rotation = 270, offset = 48.
38 -1.0, -1.0, 0.0, 0.0,
39 1.0, -1.0, 0.0, 1.0,
40 -1.0, 1.0, 1.0, 0.0,
41 1.0, 1.0, 1.0, 1.0,
42 };
43
44 static inline int offsetForRotation(int rotation) {
45 switch (rotation) {
46 case 0:
47 return 0;
48 break;
49 case 90:
50 return 16;
51 break;
52 case 180:
53 return 32;
54 break;
55 case 270:
56 return 48;
57 break;
58 default:
59 return 0;
60 break;
61 }
62 }
63
64 // The max number of command buffers in flight.
65 // For now setting it up to 1.
66 // In future we might opt in to use tripple buffering method if it improves perf ormance.
kthelgason 2017/01/24 14:18:00 I think this sentence could be made more concise:
daniela-webrtc 2017/01/25 08:46:19 Done.
67
68 static const NSInteger kMaxInflightBuffers = 1;
69
70 @interface RTCMTLRenderer ()<MTKViewDelegate>
71 @end
72
73 @implementation RTCMTLRenderer {
74 __kindof MTKView *_view;
75
76 // Controller.
77 dispatch_semaphore_t _inflight_semaphore;
78
79 // Renderer.
80 id<MTLDevice> _device;
81 id<MTLCommandQueue> _commandQueue;
82 id<MTLLibrary> _defaultLibrary;
83 id<MTLRenderPipelineState> _pipelineState;
84
85 // Textures.
86 CVMetalTextureCacheRef textureCache;
87 id<MTLTexture> yTexture;
88 id<MTLTexture> CrCbTexture;
89
90 // Buffers.
91 id<MTLBuffer> _vertexBuffer;
92
93 // RTC Frame parameters.
94 int rotation;
95 int offset;
96 }
97
98 - (instancetype)initWithView:(__kindof MTKView *)view {
99 if (self = [super init]) {
100 _view = view;
101
102 // Offset of 0 is equal to rotation of 0.
103 rotation = 0;
104 offset = 0;
105 _inflight_semaphore = dispatch_semaphore_create(kMaxInflightBuffers);
106 }
107
108 return self;
109 }
110
111 - (BOOL)setup {
112 BOOL success = NO;
113 if ([self _setupMetal] && _device) {
114 [self _setupView];
115 [self _loadAssets];
116 [self _setupBuffers];
117 [self initializeTextureCache];
118 success = YES;
119 }
120 return success;
121 }
122
123 - (BOOL)_setupMetal {
kthelgason 2017/01/24 14:17:59 We haven't really been doing the _methodName. For
daniela-webrtc 2017/01/25 08:46:19 Yes it's not common. I saw this in Apple's Metal
124 // Set the view to use the default device.
125 _device = MTLCreateSystemDefaultDevice();
126
127 // Create a new command queue.
128 _commandQueue = [_device newCommandQueue];
129
130 // Load all the shader files with a metal file extension in the project.
131 NSError *libraryError = nil;
132 NSString *libraryFile = [[NSBundle mainBundle] pathForResource:@"rtc_shaders" ofType:@"metallib"];
133 if (!libraryFile) {
134 RTCLog(@"Metal Error: library not found in main bundle.");
135 return NO;
136 }
137
138 _defaultLibrary = [_device newLibraryWithFile:libraryFile error:&libraryError] ;
139 if (!_defaultLibrary) {
140 RTCLog(@"Metal error: Failed to load library. %@", libraryError);
141 return NO;
142 }
143
144 return YES;
145 }
146
147 - (void)_setupView {
148 _view.device = _device;
149 _view.delegate = self;
150 // VERY VERY MUCHISIMO IMPORTANTE.
kthelgason 2017/01/24 14:18:00 Maybe a less flamboyant comment? :D although I do
daniela-webrtc 2017/01/25 08:46:19 Ooops! This one slipped :D was meant to be part of
151 _view.contentMode = UIViewContentModeScaleAspectFit;
152
153 _view.preferredFramesPerSecond = 30;
154 _view.autoResizeDrawable = NO;
155 }
156
157 - (void)_loadAssets {
158 // As defined in Shaders.metal.
159 id<MTLFunction> vertexFunction = [_defaultLibrary newFunctionWithName:@"vertex Passthrough"];
160 id<MTLFunction> fragmentFunction =
161 [_defaultLibrary newFunctionWithName:@"fragmentColorConversion"];
162
163 MTLRenderPipelineDescriptor *pipelineDescriptor = [[MTLRenderPipelineDescripto r alloc] init];
164 pipelineDescriptor.label = @"Pipeline";
165 pipelineDescriptor.vertexFunction = vertexFunction;
166 pipelineDescriptor.fragmentFunction = fragmentFunction;
167 pipelineDescriptor.colorAttachments[0].pixelFormat = _view.colorPixelFormat;
168 pipelineDescriptor.depthAttachmentPixelFormat = MTLPixelFormatInvalid;
169 NSError *error = nil;
170 _pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineDescrip tor error:&error];
171
172 if (!_pipelineState) {
173 RTCLog(@"Metal error: Failed to create pipeline state. %@", error);
174 }
175 }
176
177 - (void)_setupBuffers {
178 _vertexBuffer = [_device newBufferWithBytes:cubeVertexData
179 length:sizeof(cubeVertexData)
180 options:MTLResourceOptionCPUCacheModeDefau lt];
181 }
182
183 - (void)initializeTextureCache {
184 CVReturn status =
185 CVMetalTextureCacheCreate(kCFAllocatorDefault, nil, _device, nil, &texture Cache);
186 if (status != kCVReturnSuccess) {
187 RTCLog(@"Metal error: Falied to initialize metal texture cache. Return statu s is %d", status);
magjed_webrtc 2017/01/24 14:01:56 spelling nit: Failed
daniela-webrtc 2017/01/25 08:46:19 Done.
188 }
189 }
190
191 - (void)_render {
192 dispatch_semaphore_wait(_inflight_semaphore, DISPATCH_TIME_FOREVER);
193
194 id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
195 commandBuffer.label = @"RTCCommandBuffer";
196
197 __block dispatch_semaphore_t block_semaphore = _inflight_semaphore;
198 [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> _Nonnull) {
199 dispatch_semaphore_signal(block_semaphore);
200 }];
201
202 MTLRenderPassDescriptor *_renderPassDescriptor = _view.currentRenderPassDescri ptor;
203 if (_renderPassDescriptor) { // valid drawable.
204
205 id<MTLRenderCommandEncoder> renderEncoder =
206 [commandBuffer renderCommandEncoderWithDescriptor:_renderPassDescriptor] ;
207 renderEncoder.label = @"RTCEncoder";
208
209 // Set context state.
210 [renderEncoder pushDebugGroup:@"DrawFrame"];
211 [renderEncoder setRenderPipelineState:_pipelineState];
212 [renderEncoder setVertexBuffer:_vertexBuffer offset:sizeof(float[offset]) at Index:0];
213 [renderEncoder setFragmentTexture:yTexture atIndex:0];
214 [renderEncoder setFragmentTexture:CrCbTexture atIndex:1];
215
216 [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip
217 vertexStart:0
218 vertexCount:4
219 instanceCount:1];
220 [renderEncoder popDebugGroup];
221 [renderEncoder endEncoding];
222
223 [commandBuffer presentDrawable:_view.currentDrawable];
224 }
225
226 [commandBuffer commit];
227 }
228
229 #pragma mark - MTKViewDelegate
230
231 - (void)drawInMTKView:(MTKView *)view {
232 if (!yTexture && !CrCbTexture) {
233 NSLog(@"No current frame. Aborting drawinFrame:");
234 return;
235 }
236 @autoreleasepool {
237 [self _render];
238 }
239 }
240
241 - (void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size {
242 }
243
244 #pragma mark - RTCVideoRenderer
245 - (void)setSize:(CGSize)size {
246 _view.drawableSize = size;
247 [_view draw];
248 }
249
250 - (void)renderFrame:(nullable RTCVideoFrame *)frame {
251 if (frame == NULL) {
252 return;
253 }
254 [self setupSyncVariablesForFrame:frame];
kthelgason 2017/01/24 14:18:00 I don't see the point of extracting this into a me
daniela-webrtc 2017/01/25 08:46:19 It can be inlined but it was my personal preferenc
255 }
256
257 - (void)setupSyncVariablesForFrame:(nonnull RTCVideoFrame *)frame {
258 CVPixelBufferRef pixelBuffer = frame.nativeHandle;
259
260 id<MTLTexture> lumaTexture = nil;
261 id<MTLTexture> chromaTexture = nil;
262 CVMetalTextureRef outTexture;
263
264 // Luma (y) texture.
265 int lumaWidth = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0);
266 int lumaHeight = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0);
267
268 CVReturn result = CVMetalTextureCacheCreateTextureFromImage(
269 kCFAllocatorDefault, textureCache, pixelBuffer, nil, MTLPixelFormatR8Unorm , lumaWidth,
270 lumaHeight, 0, &outTexture);
magjed_webrtc 2017/01/24 14:01:56 Maybe add a comment for the literal 0: /* indexPla
daniela-webrtc 2017/01/25 08:46:19 Good idea. I've actually added a separate variable
271
272 if (result == kCVReturnSuccess) {
273 lumaTexture = CVMetalTextureGetTexture(outTexture);
274 }
275
276 CVBufferRelease(outTexture);
magjed_webrtc 2017/01/24 14:01:56 Is it ok to release |outTexture| here and keep usi
daniela-webrtc 2017/01/25 08:46:19 Not sure I understand the question. Are you asking
277 outTexture = nil;
278
279 // Chroma (CrCb) texture.
280 result = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, textur eCache, pixelBuffer,
281 nil, MTLPixelFormatRG8Unorm , lumaWidth / 2,
282 lumaHeight / 2, 1, &outText ure);
magjed_webrtc 2017/01/24 14:01:56 ditto: Maybe add a comment for the literal 1: /* i
daniela-webrtc 2017/01/25 08:46:19 ^
283 if (result == kCVReturnSuccess) {
284 chromaTexture = CVMetalTextureGetTexture(outTexture);
285 }
286 CVBufferRelease(outTexture);
287
288 if (lumaTexture != nil && chromaTexture != nil) {
289 dispatch_async(dispatch_get_main_queue(), ^{
290 yTexture = lumaTexture;
291 CrCbTexture = chromaTexture;
292 if (rotation != frame.rotation) {
293 rotation = frame.rotation;
294 offset = offsetForRotation(rotation);
295 }
296 });
297 }
298 }
299
300 - (nullable id<MTLTexture>)transformFrame:(RTCVideoFrame *)videoFrame
magjed_webrtc 2017/01/24 14:01:56 Is this function used?
daniela-webrtc 2017/01/25 08:46:19 Great catch. It was part of a previous implementat
301 toTextureIndexPlane:(int)indexPlane {
302 CVPixelBufferRef pixelBuffer = videoFrame.nativeHandle;
303
304 id<MTLTexture> mtlTexture = nil;
305 int width = CVPixelBufferGetWidthOfPlane(pixelBuffer, indexPlane);
306 int height = CVPixelBufferGetHeightOfPlane(pixelBuffer, indexPlane);
307
308 CVMetalTextureRef texture;
309
310 MTLPixelFormat format = MTLPixelFormatRG8Unorm;
311 if (indexPlane == 0) {
312 format = MTLPixelFormatR8Unorm;
313 }
314 CVReturn status =
315 CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, textureCach e, pixelBuffer, nil,
316 format, width, height, indexPlan e, &texture);
317 if (status != kCVReturnSuccess) {
318 RTCLog(@"Metal errror: Failed to create metal texture for plane index %d", i ndexPlane);
319 return nil;
320 }
321
322 mtlTexture = CVMetalTextureGetTexture(texture);
323
324 // Same like CFRelease except it can be passed NULL without crashing.
325 CVBufferRelease(texture);
326 return mtlTexture;
327 }
328 @end
OLDNEW
« no previous file with comments | « webrtc/sdk/BUILD.gn ('k') | webrtc/sdk/objc/Framework/Classes/metal/RTCMTLVideoView.m » ('j') | no next file with comments »

Powered by Google App Engine