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

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

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

Powered by Google App Engine
This is Rietveld 408576698