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

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

Issue 2651743007: Add metal view, shaders and renderer. (Closed)
Patch Set: Link metal libraries only for arm64cpu Created 3 years, 10 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
OLDNEW
(Empty)
1 /*
2 * Copyright 2017 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 "RTCNV12Renderer.h"
12
13 #import <Metal/Metal.h>
14 #import <MetalKit/MetalKit.h>
15
16 #import "WebRTC/RTCLogging.h"
17 #import "WebRTC/RTCVideoFrame.h"
18
19 static const float cubeVertexData[64] = {
20 -1.0, -1.0, 0.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1. 0, 0.0,
21
22 // rotation = 90, offset = 16.
23 -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 0.0, -1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0. 0, 0.0,
24
25 // rotation = 180, offset = 32.
26 -1.0, -1.0, 1.0, 0.0, 1.0, -1.0, 0.0, 0.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0. 0, 1.0,
27
28 // rotation = 270, offset = 48.
29 -1.0, -1.0, 0.0, 0.0, 1.0, -1.0, 0.0, 1.0, -1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1. 0, 1.0,
30 };
31
32 static inline int offsetForRotation(int rotation) {
tkchin_webrtc 2017/02/10 23:32:10 Would rotation be better as an enum? Otherwise def
daniela-webrtc 2017/02/13 12:32:06 Done.
33 switch (rotation) {
34 case 0:
35 return 0;
36 case 90:
37 return 16;
38 case 180:
39 return 32;
40 case 270:
41 return 48;
42 default:
43 return 0;
44 }
45 }
46
47 // The max number of command buffers in flight.
48 // For now setting it up to 1.
49 // In future we might use tripple buffering method if it improves performance.
50
51 static const NSInteger kMaxInflightBuffers = 1;
52
53 @interface RTCNV12Renderer ()<MTKViewDelegate>
tkchin_webrtc 2017/02/10 23:32:10 space after () () <MTK
54 @end
55
56 @implementation RTCNV12Renderer {
57 __kindof MTKView *_view;
58
59 // Controller.
60 dispatch_semaphore_t _inflight_semaphore;
61
62 // Renderer.
63 id<MTLDevice> _device;
64 id<MTLCommandQueue> _commandQueue;
65 id<MTLLibrary> _defaultLibrary;
66 id<MTLRenderPipelineState> _pipelineState;
67
68 // Textures.
69 CVMetalTextureCacheRef textureCache;
70 id<MTLTexture> yTexture;
71 id<MTLTexture> CrCbTexture;
72
73 // Buffers.
74 id<MTLBuffer> _vertexBuffer;
75
76 // RTC Frame parameters.
77 int offset;
78 }
79
80 - (instancetype)initWithView:(__kindof MTKView *)view {
tkchin_webrtc 2017/02/10 23:32:10 I don't think renderer should have dependency on h
daniela-webrtc 2017/02/13 12:32:06 Not sure how to avoid this dependency without expo
81 if (self = [super init]) {
82 _view = view;
83
84 // Offset of 0 is equal to rotation of 0.
85 offset = 0;
86 _inflight_semaphore = dispatch_semaphore_create(kMaxInflightBuffers);
87 }
88
89 return self;
90 }
91
92 - (BOOL)setup {
93 BOOL success = NO;
94 if ([self _setupMetal] && _device) {
95 [self _setupView];
tkchin_webrtc 2017/02/10 23:32:10 don't use _ in method names If they are meant to
daniela-webrtc 2017/02/13 12:32:06 This is taken from some of the Apple examples wher
tkchin_webrtc 2017/02/14 00:23:55 I would recommend against it. _ frequently is used
96 [self _loadAssets];
97 [self _setupBuffers];
98 [self initializeTextureCache];
99 success = YES;
100 }
101 return success;
102 }
103
104 - (BOOL)_setupMetal {
105 // Set the view to use the default device.
106 _device = MTLCreateSystemDefaultDevice();
107
108 // Create a new command queue.
109 _commandQueue = [_device newCommandQueue];
110
111 // Load all the shader files with a metal file extension in the project.
112 NSError *libraryError = nil;
113 NSBundle *frameworkBundle = [NSBundle bundleWithIdentifier:@"org.webrtc.WebRTC "];
tkchin_webrtc 2017/02/10 23:32:10 This should be a predefined constant somewhere tha
daniela-webrtc 2017/02/13 12:32:06 I'll think a bit how to best implement this. Ideal
114 NSString *libraryFile = [frameworkBundle pathForResource:@"rtc_shaders" ofType :@"metallib"];
115 if (!libraryFile) {
116 RTCLog(
117 @"Metal Error: library not found in framework bundle with identifier org .webrtc.WebRTC.");
118 return NO;
119 }
120
121 _defaultLibrary = [_device newLibraryWithFile:libraryFile error:&libraryError] ;
122 if (!_defaultLibrary) {
123 RTCLog(@"Metal error: Failed to load library. %@", libraryError);
124 return NO;
125 }
126
127 return YES;
128 }
129
130 - (void)_setupView {
131 _view.device = _device;
132 _view.delegate = self;
133 // This is very important, should not be removed.
134 _view.contentMode = UIViewContentModeScaleAspectFit;
135
136 _view.preferredFramesPerSecond = 30;
137 _view.autoResizeDrawable = NO;
138 }
139
140 - (void)_loadAssets {
141 // As defined in Shaders.metal.
142 id<MTLFunction> vertexFunction = [_defaultLibrary newFunctionWithName:@"vertex Passthrough"];
143 id<MTLFunction> fragmentFunction =
144 [_defaultLibrary newFunctionWithName:@"fragmentColorConversion"];
145
146 MTLRenderPipelineDescriptor *pipelineDescriptor = [[MTLRenderPipelineDescripto r alloc] init];
147 pipelineDescriptor.label = @"Pipeline";
148 pipelineDescriptor.vertexFunction = vertexFunction;
149 pipelineDescriptor.fragmentFunction = fragmentFunction;
150 pipelineDescriptor.colorAttachments[0].pixelFormat = _view.colorPixelFormat;
151 pipelineDescriptor.depthAttachmentPixelFormat = MTLPixelFormatInvalid;
152 NSError *error = nil;
153 _pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineDescrip tor error:&error];
154
155 if (!_pipelineState) {
156 RTCLog(@"Metal error: Failed to create pipeline state. %@", error);
157 }
158 }
159
160 - (void)_setupBuffers {
161 _vertexBuffer = [_device newBufferWithBytes:cubeVertexData
162 length:sizeof(cubeVertexData)
163 options:MTLResourceOptionCPUCacheModeDefau lt];
164 }
165
166 - (void)initializeTextureCache {
167 CVReturn status =
168 CVMetalTextureCacheCreate(kCFAllocatorDefault, nil, _device, nil, &texture Cache);
169 if (status != kCVReturnSuccess) {
170 RTCLog(@"Metal error: Failed to initialize metal texture cache. Return statu s is %d", status);
171 }
172 }
173
174 - (void)_render {
175 dispatch_semaphore_wait(_inflight_semaphore, DISPATCH_TIME_FOREVER);
176
177 id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
178 commandBuffer.label = @"RTCCommandBuffer";
179
180 __block dispatch_semaphore_t block_semaphore = _inflight_semaphore;
181 [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> _Nonnull) {
182 dispatch_semaphore_signal(block_semaphore);
183 }];
184
185 MTLRenderPassDescriptor *_renderPassDescriptor = _view.currentRenderPassDescri ptor;
186 if (_renderPassDescriptor) { // Valid drawable.
187
188 id<MTLRenderCommandEncoder> renderEncoder =
189 [commandBuffer renderCommandEncoderWithDescriptor:_renderPassDescriptor] ;
190 renderEncoder.label = @"RTCEncoder";
191
192 // Set context state.
193 [renderEncoder pushDebugGroup:@"DrawFrame"];
194 [renderEncoder setRenderPipelineState:_pipelineState];
195 [renderEncoder setVertexBuffer:_vertexBuffer offset:offset * sizeof(float) a tIndex:0];
196 [renderEncoder setFragmentTexture:yTexture atIndex:0];
197 [renderEncoder setFragmentTexture:CrCbTexture atIndex:1];
198
199 [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip
200 vertexStart:0
201 vertexCount:4
202 instanceCount:1];
203 [renderEncoder popDebugGroup];
204 [renderEncoder endEncoding];
205
206 [commandBuffer presentDrawable:_view.currentDrawable];
207 }
208
209 [commandBuffer commit];
210 }
211
212 #pragma mark - MTKViewDelegate
213
214 - (void)drawInMTKView:(MTKView *)view {
215 if (!yTexture && !CrCbTexture) {
216 NSLog(@"No current frame. Aborting drawinFrame:");
217 return;
218 }
219 @autoreleasepool {
220 [self _render];
221 }
222 }
223
224 - (void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size {
225 }
226
227 #pragma mark - RTCVideoRenderer
tkchin_webrtc 2017/02/10 23:32:10 nit: newline after pragma
daniela-webrtc 2017/02/13 12:32:06 Done.
228 - (void)setSize:(CGSize)size {
229 _view.drawableSize = size;
230 [_view draw];
231 }
232
233 - (void)renderFrame:(nullable RTCVideoFrame *)frame {
234 if (frame == NULL) {
235 return;
236 }
237 [self setupSyncVariablesForFrame:frame];
238 }
239
240 - (void)setupSyncVariablesForFrame:(nonnull RTCVideoFrame *)frame {
241 CVPixelBufferRef pixelBuffer = frame.nativeHandle;
242
243 id<MTLTexture> lumaTexture = nil;
244 id<MTLTexture> chromaTexture = nil;
245 CVMetalTextureRef outTexture;
246
247 // Luma (y) texture.
248 int lumaWidth = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0);
249 int lumaHeight = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0);
250
251 int indexPlane = 0;
252 CVReturn result = CVMetalTextureCacheCreateTextureFromImage(
253 kCFAllocatorDefault, textureCache, pixelBuffer, nil, MTLPixelFormatR8Unorm , lumaWidth,
254 lumaHeight, indexPlane, &outTexture);
255
256 if (result == kCVReturnSuccess) {
257 lumaTexture = CVMetalTextureGetTexture(outTexture);
258 }
259
260 CVBufferRelease(outTexture);
261 outTexture = nil;
262
263 // Chroma (CrCb) texture.
264 indexPlane = 1;
265 result = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, textur eCache, pixelBuffer,
266 nil, MTLPixelFormatRG8Unorm , lumaWidth / 2,
267 lumaHeight / 2, indexPlane, &outTexture);
268 if (result == kCVReturnSuccess) {
269 chromaTexture = CVMetalTextureGetTexture(outTexture);
270 }
271 CVBufferRelease(outTexture);
272
273 if (lumaTexture != nil && chromaTexture != nil) {
274 dispatch_async(dispatch_get_main_queue(), ^{
275 yTexture = lumaTexture;
276 CrCbTexture = chromaTexture;
277 offset = offsetForRotation(frame.rotation);
278 });
279 }
280 }
281
282 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698