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

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

Issue 2784243003: iOS/MacOS:Refactor metal rendering by extracting common implementation (Closed)
Patch Set: Created 3 years, 8 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
1 /* 1 /*
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved. 2 * Copyright 2017 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 "RTCMTLI420Renderer.h" 11 #import "RTCMTLI420Renderer.h"
12 12
13 #import <Metal/Metal.h> 13 #import <Metal/Metal.h>
14 #import <MetalKit/MetalKit.h> 14 #import <MetalKit/MetalKit.h>
15 15
16 #import "WebRTC/RTCLogging.h" 16 #import "WebRTC/RTCLogging.h"
17 #import "WebRTC/RTCVideoFrame.h" 17 #import "WebRTC/RTCVideoFrame.h"
18 18
19 #include "webrtc/api/video/video_rotation.h" 19 #import "RTCMTLRenderer+Private.h"
20 20
21 #define MTL_STRINGIFY(s) @ #s 21 #define MTL_STRINGIFY(s) @ #s
22 22
23 // As defined in shaderSource.
24 static NSString *const vertexFunctionName = @"vertexPassthrough";
25 static NSString *const fragmentFunctionName = @"fragmentColorConversion";
26
27 static NSString *const pipelineDescriptorLabel = @"RTCPipeline";
28 static NSString *const commandBufferLabel = @"RTCCommandBuffer";
29 static NSString *const renderEncoderLabel = @"RTCEncoder";
30 static NSString *const renderEncoderDebugGroup = @"RTCDrawFrame";
31
32 static const float cubeVertexData[64] = {
33 -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,
34
35 // rotation = 90, offset = 16.
36 -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,
37
38 // rotation = 180, offset = 32.
39 -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,
40
41 // rotation = 270, offset = 48.
42 -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,
43 };
44
45 static inline int offsetForRotation(webrtc::VideoRotation rotation) {
46 switch (rotation) {
47 case webrtc::kVideoRotation_0:
48 return 0;
49 case webrtc::kVideoRotation_90:
50 return 16;
51 case webrtc::kVideoRotation_180:
52 return 32;
53 case webrtc::kVideoRotation_270:
54 return 48;
55 }
56 return 0;
57 }
58
59 static NSString *const shaderSource = MTL_STRINGIFY( 23 static NSString *const shaderSource = MTL_STRINGIFY(
60 using namespace metal; typedef struct { 24 using namespace metal; typedef struct {
61 packed_float2 position; 25 packed_float2 position;
62 packed_float2 texcoord; 26 packed_float2 texcoord;
63 } Vertex; 27 } Vertex;
64 28
65 typedef struct { 29 typedef struct {
66 float4 position[[position]]; 30 float4 position[[position]];
67 float2 texcoord; 31 float2 texcoord;
68 } Varyings; 32 } Varyings;
(...skipping 27 matching lines...) Expand all
96 v = v - 0.5; 60 v = v - 0.5;
97 r = y + 1.403 * v; 61 r = y + 1.403 * v;
98 g = y - 0.344 * u - 0.714 * v; 62 g = y - 0.344 * u - 0.714 * v;
99 b = y + 1.770 * u; 63 b = y + 1.770 * u;
100 64
101 float4 out = float4(r, g, b, 1.0); 65 float4 out = float4(r, g, b, 1.0);
102 66
103 return half4(out); 67 return half4(out);
104 }); 68 });
105 69
106 // The max number of command buffers in flight.
107 // For now setting it up to 1.
108 // In future we might use triple buffering method if it improves performance.
109
110 static const NSInteger kMaxInflightBuffers = 1;
111
112 @implementation RTCMTLI420Renderer { 70 @implementation RTCMTLI420Renderer {
113 __kindof MTKView *_view;
114
115 // Controller.
116 dispatch_semaphore_t _inflight_semaphore;
117
118 // Renderer.
119 id<MTLDevice> _device;
120 id<MTLCommandQueue> _commandQueue;
121 id<MTLLibrary> _defaultLibrary;
122 id<MTLRenderPipelineState> _pipelineState;
123
124 // Textures. 71 // Textures.
125 id<MTLTexture> _yTexture; 72 id<MTLTexture> _yTexture;
126 id<MTLTexture> _uTexture; 73 id<MTLTexture> _uTexture;
127 id<MTLTexture> _vTexture; 74 id<MTLTexture> _vTexture;
128 75
129 MTLTextureDescriptor *_descriptor; 76 MTLTextureDescriptor *_descriptor;
130 MTLTextureDescriptor *_chromaDescriptor; 77 MTLTextureDescriptor *_chromaDescriptor;
131 78
132 int _width; 79 int _width;
133 int _height; 80 int _height;
134 int _chromaWidth; 81 int _chromaWidth;
135 int _chromaHeight; 82 int _chromaHeight;
136
137 // Buffers.
138 id<MTLBuffer> _vertexBuffer;
139
140 // RTC Frame parameters.
141 int _offset;
142 } 83 }
143 84
144 - (instancetype)init { 85 #pragma mark - Virtual
145 if (self = [super init]) {
146 // Offset of 0 is equal to rotation of 0.
147 _offset = 0;
148 _inflight_semaphore = dispatch_semaphore_create(kMaxInflightBuffers);
149 }
150 86
151 return self; 87 - (NSString *)shaderSource {
88 return shaderSource;
152 } 89 }
153 90
154 - (BOOL)addRenderingDestination:(__kindof MTKView *)view { 91 - (BOOL)setupTexturesForFrame:(nonnull RTCVideoFrame *)frame {
155 return [self setupWithView:view]; 92 [super setupTexturesForFrame:frame];
156 }
157 93
158 #pragma mark - Private 94 id<MTLDevice> device = [self currentMetalDevice];
159 95 if (!device) {
160 - (BOOL)setupWithView:(__kindof MTKView *)view {
161 BOOL success = NO;
162 if ([self setupMetal]) {
163 [self setupView:view];
164 [self loadAssets];
165 [self setupBuffers];
166 success = YES;
167 }
168 return success;
169 }
170
171 #pragma mark - GPU methods
172
173 - (BOOL)setupMetal {
174 // Set the view to use the default device.
175 _device = MTLCreateSystemDefaultDevice();
176 if (!_device) {
177 return NO; 96 return NO;
178 } 97 }
179 98
180 // Create a new command queue.
181 _commandQueue = [_device newCommandQueue];
182
183 // Load metal library from source.
184 NSError *libraryError = nil;
185
186 id<MTLLibrary> sourceLibrary =
187 [_device newLibraryWithSource:shaderSource options:NULL error:&libraryErro r];
188
189 if (libraryError) {
190 RTCLogError(@"Metal: Library with source failed\n%@", libraryError);
191 return NO;
192 }
193
194 if (!sourceLibrary) {
195 RTCLogError(@"Metal: Failed to load library. %@", libraryError);
196 return NO;
197 }
198 _defaultLibrary = sourceLibrary;
199
200 return YES;
201 }
202
203 - (void)setupView:(__kindof MTKView *)view {
204 view.device = _device;
205
206 view.preferredFramesPerSecond = 30;
207 view.autoResizeDrawable = NO;
208
209 // We need to keep reference to the view as it's needed down the rendering pip eline.
210 _view = view;
211 }
212
213 - (void)loadAssets {
214 id<MTLFunction> vertexFunction = [_defaultLibrary newFunctionWithName:vertexFu nctionName];
215 id<MTLFunction> fragmentFunction = [_defaultLibrary newFunctionWithName:fragme ntFunctionName];
216
217 MTLRenderPipelineDescriptor *pipelineDescriptor = [[MTLRenderPipelineDescripto r alloc] init];
218 pipelineDescriptor.label = pipelineDescriptorLabel;
219 pipelineDescriptor.vertexFunction = vertexFunction;
220 pipelineDescriptor.fragmentFunction = fragmentFunction;
221 pipelineDescriptor.colorAttachments[0].pixelFormat = _view.colorPixelFormat;
222 pipelineDescriptor.depthAttachmentPixelFormat = MTLPixelFormatInvalid;
223 NSError *error = nil;
224 _pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineDescrip tor error:&error];
225
226 if (!_pipelineState) {
227 RTCLogError(@"Metal: Failed to create pipeline state. %@", error);
228 }
229 }
230
231 - (void)setupBuffers {
232 _vertexBuffer = [_device newBufferWithBytes:cubeVertexData
233 length:sizeof(cubeVertexData)
234 options:MTLStorageModeShared];
235 }
236
237 - (void)render {
238 dispatch_semaphore_wait(_inflight_semaphore, DISPATCH_TIME_FOREVER);
239
240 id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
241 commandBuffer.label = commandBufferLabel;
242
243 __block dispatch_semaphore_t block_semaphore = _inflight_semaphore;
244 [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> _Nonnull) {
245 dispatch_semaphore_signal(block_semaphore);
246 }];
247
248 MTLRenderPassDescriptor *_renderPassDescriptor = _view.currentRenderPassDescri ptor;
249 if (_renderPassDescriptor) { // Valid drawable.
250 id<MTLRenderCommandEncoder> renderEncoder =
251 [commandBuffer renderCommandEncoderWithDescriptor:_renderPassDescriptor] ;
252 renderEncoder.label = renderEncoderLabel;
253
254 // Set context state.
255 [renderEncoder pushDebugGroup:renderEncoderDebugGroup];
256 [renderEncoder setRenderPipelineState:_pipelineState];
257 [renderEncoder setVertexBuffer:_vertexBuffer offset:_offset * sizeof(float) atIndex:0];
258 [renderEncoder setFragmentTexture:_yTexture atIndex:0];
259 [renderEncoder setFragmentTexture:_uTexture atIndex:1];
260 [renderEncoder setFragmentTexture:_vTexture atIndex:2];
261
262 [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip
263 vertexStart:0
264 vertexCount:4
265 instanceCount:1];
266 [renderEncoder popDebugGroup];
267 [renderEncoder endEncoding];
268
269 [commandBuffer presentDrawable:_view.currentDrawable];
270 }
271
272 [commandBuffer commit];
273 }
274
275 #pragma mark - RTCMTLRenderer
276
277 - (void)drawFrame:(RTCVideoFrame *)frame {
278 if (!frame) {
279 return;
280 }
281 if ([self setupTexturesForFrame:frame]) {
282 @autoreleasepool {
283 [self render];
284 }
285 }
286 }
287
288 - (BOOL)setupTexturesForFrame:(nonnull RTCVideoFrame *)frame {
289 // Luma (y) texture. 99 // Luma (y) texture.
290
291 if (!_descriptor || (_width != frame.width && _height != frame.height)) { 100 if (!_descriptor || (_width != frame.width && _height != frame.height)) {
292 _width = frame.width; 101 _width = frame.width;
293 _height = frame.height; 102 _height = frame.height;
294 _descriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPi xelFormatR8Unorm 103 _descriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPi xelFormatR8Unorm
295 width:_widt h 104 width:_widt h
296 height:_heig ht 105 height:_heig ht
297 mipmapped:NO]; 106 mipmapped:NO];
298 _descriptor.usage = MTLTextureUsageShaderRead; 107 _descriptor.usage = MTLTextureUsageShaderRead;
299 _yTexture = [_device newTextureWithDescriptor:_descriptor]; 108 _yTexture = [device newTextureWithDescriptor:_descriptor];
300 } 109 }
301 110
302 // Chroma (u,v) textures 111 // Chroma (u,v) textures
303 [_yTexture replaceRegion:MTLRegionMake2D(0, 0, _width, _height) 112 [_yTexture replaceRegion:MTLRegionMake2D(0, 0, _width, _height)
304 mipmapLevel:0 113 mipmapLevel:0
305 withBytes:frame.dataY 114 withBytes:frame.dataY
306 bytesPerRow:frame.strideY]; 115 bytesPerRow:frame.strideY];
307 116
308 if (!_chromaDescriptor || 117 if (!_chromaDescriptor ||
309 (_chromaWidth != frame.width / 2 && _chromaHeight != frame.height / 2)) { 118 (_chromaWidth != frame.width / 2 && _chromaHeight != frame.height / 2)) {
310 _chromaWidth = frame.width / 2; 119 _chromaWidth = frame.width / 2;
311 _chromaHeight = frame.height / 2; 120 _chromaHeight = frame.height / 2;
312 _chromaDescriptor = 121 _chromaDescriptor =
313 [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR 8Unorm 122 [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR 8Unorm
314 width:_chromaWidth 123 width:_chromaWidth
315 height:_chromaHeight 124 height:_chromaHeight
316 mipmapped:NO]; 125 mipmapped:NO];
317 _chromaDescriptor.usage = MTLTextureUsageShaderRead; 126 _chromaDescriptor.usage = MTLTextureUsageShaderRead;
318 _uTexture = [_device newTextureWithDescriptor:_chromaDescriptor]; 127 _uTexture = [device newTextureWithDescriptor:_chromaDescriptor];
319 _vTexture = [_device newTextureWithDescriptor:_chromaDescriptor]; 128 _vTexture = [device newTextureWithDescriptor:_chromaDescriptor];
320 } 129 }
321 130
322 [_uTexture replaceRegion:MTLRegionMake2D(0, 0, _chromaWidth, _chromaHeight) 131 [_uTexture replaceRegion:MTLRegionMake2D(0, 0, _chromaWidth, _chromaHeight)
323 mipmapLevel:0 132 mipmapLevel:0
324 withBytes:frame.dataU 133 withBytes:frame.dataU
325 bytesPerRow:frame.strideU]; 134 bytesPerRow:frame.strideU];
326 [_vTexture replaceRegion:MTLRegionMake2D(0, 0, _chromaWidth, _chromaHeight) 135 [_vTexture replaceRegion:MTLRegionMake2D(0, 0, _chromaWidth, _chromaHeight)
327 mipmapLevel:0 136 mipmapLevel:0
328 withBytes:frame.dataV 137 withBytes:frame.dataV
329 bytesPerRow:frame.strideV]; 138 bytesPerRow:frame.strideV];
330 139
331 _offset = offsetForRotation((webrtc::VideoRotation)frame.rotation);
332
333 return (_uTexture != nil) && (_yTexture != nil) && (_vTexture != nil); 140 return (_uTexture != nil) && (_yTexture != nil) && (_vTexture != nil);
334 } 141 }
335 142
143 - (void)uploadTexturesToRenderEncoder:(id<MTLRenderCommandEncoder>)renderEncoder {
144 [renderEncoder setFragmentTexture:_yTexture atIndex:0];
145 [renderEncoder setFragmentTexture:_uTexture atIndex:1];
146 [renderEncoder setFragmentTexture:_vTexture atIndex:2];
147 }
148
336 @end 149 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698