blob: f7a75d8056c2cfaedd75295edfe28f70108cffd9 [file] [log] [blame]
denicija124a6fc2017-03-31 02:47:29 -07001/*
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 "RTCMTLI420Renderer.h"
Anders Carlssone5960ce2017-06-22 15:26:30 +020012#import "WebRTC/RTCVideoFrameBuffer.h"
denicija124a6fc2017-03-31 02:47:29 -070013
14#import <Metal/Metal.h>
15#import <MetalKit/MetalKit.h>
16
17#import "WebRTC/RTCLogging.h"
18#import "WebRTC/RTCVideoFrame.h"
19
denicijad2088152017-04-28 02:14:54 -070020#import "RTCMTLRenderer+Private.h"
denicija124a6fc2017-03-31 02:47:29 -070021
denicija124a6fc2017-03-31 02:47:29 -070022static NSString *const shaderSource = MTL_STRINGIFY(
Peter Hanspers1c62b982018-05-03 14:06:04 +020023 using namespace metal;
24
25 typedef struct {
denicija124a6fc2017-03-31 02:47:29 -070026 packed_float2 position;
27 packed_float2 texcoord;
28 } Vertex;
29
30 typedef struct {
31 float4 position[[position]];
32 float2 texcoord;
33 } Varyings;
34
35 vertex Varyings vertexPassthrough(device Vertex * verticies[[buffer(0)]],
36 unsigned int vid[[vertex_id]]) {
37 Varyings out;
38 device Vertex &v = verticies[vid];
39 out.position = float4(float2(v.position), 0.0, 1.0);
40 out.texcoord = v.texcoord;
41
42 return out;
43 }
44
45 fragment half4 fragmentColorConversion(
46 Varyings in[[stage_in]], texture2d<float, access::sample> textureY[[texture(0)]],
47 texture2d<float, access::sample> textureU[[texture(1)]],
48 texture2d<float, access::sample> textureV[[texture(2)]]) {
49 constexpr sampler s(address::clamp_to_edge, filter::linear);
50 float y;
51 float u;
52 float v;
53 float r;
54 float g;
55 float b;
56 // Conversion for YUV to rgb from http://www.fourcc.org/fccyvrgb.php
57 y = textureY.sample(s, in.texcoord).r;
58 u = textureU.sample(s, in.texcoord).r;
59 v = textureV.sample(s, in.texcoord).r;
60 u = u - 0.5;
61 v = v - 0.5;
62 r = y + 1.403 * v;
63 g = y - 0.344 * u - 0.714 * v;
64 b = y + 1.770 * u;
65
66 float4 out = float4(r, g, b, 1.0);
67
68 return half4(out);
69 });
70
denicija124a6fc2017-03-31 02:47:29 -070071@implementation RTCMTLI420Renderer {
denicija124a6fc2017-03-31 02:47:29 -070072 // Textures.
73 id<MTLTexture> _yTexture;
74 id<MTLTexture> _uTexture;
75 id<MTLTexture> _vTexture;
76
77 MTLTextureDescriptor *_descriptor;
78 MTLTextureDescriptor *_chromaDescriptor;
79
80 int _width;
81 int _height;
82 int _chromaWidth;
83 int _chromaHeight;
denicija124a6fc2017-03-31 02:47:29 -070084}
85
denicijad2088152017-04-28 02:14:54 -070086#pragma mark - Virtual
denicija124a6fc2017-03-31 02:47:29 -070087
denicijad2088152017-04-28 02:14:54 -070088- (NSString *)shaderSource {
89 return shaderSource;
denicija124a6fc2017-03-31 02:47:29 -070090}
91
Peter Hanspers7af087a2018-06-12 14:14:48 +020092- (void)getWidth:(nonnull int *)width
93 height:(nonnull int *)height
94 cropWidth:(nonnull int *)cropWidth
95 cropHeight:(nonnull int *)cropHeight
96 cropX:(nonnull int *)cropX
97 cropY:(nonnull int *)cropY
98 ofFrame:(nonnull RTCVideoFrame *)frame {
99 *width = frame.width;
100 *height = frame.height;
101 *cropWidth = frame.width;
102 *cropHeight = frame.height;
103 *cropX = 0;
104 *cropY = 0;
105}
106
denicija124a6fc2017-03-31 02:47:29 -0700107- (BOOL)setupTexturesForFrame:(nonnull RTCVideoFrame *)frame {
Peter Hanspers5daaf7d2018-06-01 10:34:37 +0200108 if (![super setupTexturesForFrame:frame]) {
109 return NO;
110 }
denicija124a6fc2017-03-31 02:47:29 -0700111
denicijad2088152017-04-28 02:14:54 -0700112 id<MTLDevice> device = [self currentMetalDevice];
113 if (!device) {
114 return NO;
115 }
116
Anders Carlssone5960ce2017-06-22 15:26:30 +0200117 id<RTCI420Buffer> buffer = [frame.buffer toI420];
118
denicijad2088152017-04-28 02:14:54 -0700119 // Luma (y) texture.
denicija124a6fc2017-03-31 02:47:29 -0700120 if (!_descriptor || (_width != frame.width && _height != frame.height)) {
121 _width = frame.width;
122 _height = frame.height;
123 _descriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Unorm
124 width:_width
125 height:_height
126 mipmapped:NO];
127 _descriptor.usage = MTLTextureUsageShaderRead;
denicijad2088152017-04-28 02:14:54 -0700128 _yTexture = [device newTextureWithDescriptor:_descriptor];
denicija124a6fc2017-03-31 02:47:29 -0700129 }
130
131 // Chroma (u,v) textures
132 [_yTexture replaceRegion:MTLRegionMake2D(0, 0, _width, _height)
133 mipmapLevel:0
Anders Carlssone5960ce2017-06-22 15:26:30 +0200134 withBytes:buffer.dataY
135 bytesPerRow:buffer.strideY];
denicija124a6fc2017-03-31 02:47:29 -0700136
137 if (!_chromaDescriptor ||
138 (_chromaWidth != frame.width / 2 && _chromaHeight != frame.height / 2)) {
139 _chromaWidth = frame.width / 2;
140 _chromaHeight = frame.height / 2;
141 _chromaDescriptor =
142 [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Unorm
143 width:_chromaWidth
144 height:_chromaHeight
145 mipmapped:NO];
146 _chromaDescriptor.usage = MTLTextureUsageShaderRead;
denicijad2088152017-04-28 02:14:54 -0700147 _uTexture = [device newTextureWithDescriptor:_chromaDescriptor];
148 _vTexture = [device newTextureWithDescriptor:_chromaDescriptor];
denicija124a6fc2017-03-31 02:47:29 -0700149 }
150
151 [_uTexture replaceRegion:MTLRegionMake2D(0, 0, _chromaWidth, _chromaHeight)
152 mipmapLevel:0
Anders Carlssone5960ce2017-06-22 15:26:30 +0200153 withBytes:buffer.dataU
154 bytesPerRow:buffer.strideU];
denicija124a6fc2017-03-31 02:47:29 -0700155 [_vTexture replaceRegion:MTLRegionMake2D(0, 0, _chromaWidth, _chromaHeight)
156 mipmapLevel:0
Anders Carlssone5960ce2017-06-22 15:26:30 +0200157 withBytes:buffer.dataV
158 bytesPerRow:buffer.strideV];
denicija124a6fc2017-03-31 02:47:29 -0700159
denicija124a6fc2017-03-31 02:47:29 -0700160 return (_uTexture != nil) && (_yTexture != nil) && (_vTexture != nil);
161}
162
denicijad2088152017-04-28 02:14:54 -0700163- (void)uploadTexturesToRenderEncoder:(id<MTLRenderCommandEncoder>)renderEncoder {
164 [renderEncoder setFragmentTexture:_yTexture atIndex:0];
165 [renderEncoder setFragmentTexture:_uTexture atIndex:1];
166 [renderEncoder setFragmentTexture:_vTexture atIndex:2];
167}
168
denicija124a6fc2017-03-31 02:47:29 -0700169@end