blob: 03a381fc512845738e30aea3f28b9ce0ea7de282 [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
92- (BOOL)setupTexturesForFrame:(nonnull RTCVideoFrame *)frame {
Peter Hanspers5daaf7d2018-06-01 10:34:37 +020093 if (![super setupTexturesForFrame:frame]) {
94 return NO;
95 }
denicija124a6fc2017-03-31 02:47:29 -070096
denicijad2088152017-04-28 02:14:54 -070097 id<MTLDevice> device = [self currentMetalDevice];
98 if (!device) {
99 return NO;
100 }
101
Anders Carlssone5960ce2017-06-22 15:26:30 +0200102 id<RTCI420Buffer> buffer = [frame.buffer toI420];
103
denicijad2088152017-04-28 02:14:54 -0700104 // Luma (y) texture.
denicija124a6fc2017-03-31 02:47:29 -0700105 if (!_descriptor || (_width != frame.width && _height != frame.height)) {
106 _width = frame.width;
107 _height = frame.height;
108 _descriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Unorm
109 width:_width
110 height:_height
111 mipmapped:NO];
112 _descriptor.usage = MTLTextureUsageShaderRead;
denicijad2088152017-04-28 02:14:54 -0700113 _yTexture = [device newTextureWithDescriptor:_descriptor];
denicija124a6fc2017-03-31 02:47:29 -0700114 }
115
116 // Chroma (u,v) textures
117 [_yTexture replaceRegion:MTLRegionMake2D(0, 0, _width, _height)
118 mipmapLevel:0
Anders Carlssone5960ce2017-06-22 15:26:30 +0200119 withBytes:buffer.dataY
120 bytesPerRow:buffer.strideY];
denicija124a6fc2017-03-31 02:47:29 -0700121
122 if (!_chromaDescriptor ||
123 (_chromaWidth != frame.width / 2 && _chromaHeight != frame.height / 2)) {
124 _chromaWidth = frame.width / 2;
125 _chromaHeight = frame.height / 2;
126 _chromaDescriptor =
127 [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Unorm
128 width:_chromaWidth
129 height:_chromaHeight
130 mipmapped:NO];
131 _chromaDescriptor.usage = MTLTextureUsageShaderRead;
denicijad2088152017-04-28 02:14:54 -0700132 _uTexture = [device newTextureWithDescriptor:_chromaDescriptor];
133 _vTexture = [device newTextureWithDescriptor:_chromaDescriptor];
denicija124a6fc2017-03-31 02:47:29 -0700134 }
135
136 [_uTexture replaceRegion:MTLRegionMake2D(0, 0, _chromaWidth, _chromaHeight)
137 mipmapLevel:0
Anders Carlssone5960ce2017-06-22 15:26:30 +0200138 withBytes:buffer.dataU
139 bytesPerRow:buffer.strideU];
denicija124a6fc2017-03-31 02:47:29 -0700140 [_vTexture replaceRegion:MTLRegionMake2D(0, 0, _chromaWidth, _chromaHeight)
141 mipmapLevel:0
Anders Carlssone5960ce2017-06-22 15:26:30 +0200142 withBytes:buffer.dataV
143 bytesPerRow:buffer.strideV];
denicija124a6fc2017-03-31 02:47:29 -0700144
denicija124a6fc2017-03-31 02:47:29 -0700145 return (_uTexture != nil) && (_yTexture != nil) && (_vTexture != nil);
146}
147
denicijad2088152017-04-28 02:14:54 -0700148- (void)uploadTexturesToRenderEncoder:(id<MTLRenderCommandEncoder>)renderEncoder {
149 [renderEncoder setFragmentTexture:_yTexture atIndex:0];
150 [renderEncoder setFragmentTexture:_uTexture atIndex:1];
151 [renderEncoder setFragmentTexture:_vTexture atIndex:2];
152}
153
denicija124a6fc2017-03-31 02:47:29 -0700154@end