blob: ae5525889e7e8f255bc1ecdbe33501eb1af4d3a4 [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 {
denicijad2088152017-04-28 02:14:54 -070093 [super setupTexturesForFrame:frame];
denicija124a6fc2017-03-31 02:47:29 -070094
denicijad2088152017-04-28 02:14:54 -070095 id<MTLDevice> device = [self currentMetalDevice];
96 if (!device) {
97 return NO;
98 }
99
Anders Carlssone5960ce2017-06-22 15:26:30 +0200100 id<RTCI420Buffer> buffer = [frame.buffer toI420];
101
denicijad2088152017-04-28 02:14:54 -0700102 // Luma (y) texture.
denicija124a6fc2017-03-31 02:47:29 -0700103 if (!_descriptor || (_width != frame.width && _height != frame.height)) {
104 _width = frame.width;
105 _height = frame.height;
106 _descriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Unorm
107 width:_width
108 height:_height
109 mipmapped:NO];
110 _descriptor.usage = MTLTextureUsageShaderRead;
denicijad2088152017-04-28 02:14:54 -0700111 _yTexture = [device newTextureWithDescriptor:_descriptor];
denicija124a6fc2017-03-31 02:47:29 -0700112 }
113
114 // Chroma (u,v) textures
115 [_yTexture replaceRegion:MTLRegionMake2D(0, 0, _width, _height)
116 mipmapLevel:0
Anders Carlssone5960ce2017-06-22 15:26:30 +0200117 withBytes:buffer.dataY
118 bytesPerRow:buffer.strideY];
denicija124a6fc2017-03-31 02:47:29 -0700119
120 if (!_chromaDescriptor ||
121 (_chromaWidth != frame.width / 2 && _chromaHeight != frame.height / 2)) {
122 _chromaWidth = frame.width / 2;
123 _chromaHeight = frame.height / 2;
124 _chromaDescriptor =
125 [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Unorm
126 width:_chromaWidth
127 height:_chromaHeight
128 mipmapped:NO];
129 _chromaDescriptor.usage = MTLTextureUsageShaderRead;
denicijad2088152017-04-28 02:14:54 -0700130 _uTexture = [device newTextureWithDescriptor:_chromaDescriptor];
131 _vTexture = [device newTextureWithDescriptor:_chromaDescriptor];
denicija124a6fc2017-03-31 02:47:29 -0700132 }
133
134 [_uTexture replaceRegion:MTLRegionMake2D(0, 0, _chromaWidth, _chromaHeight)
135 mipmapLevel:0
Anders Carlssone5960ce2017-06-22 15:26:30 +0200136 withBytes:buffer.dataU
137 bytesPerRow:buffer.strideU];
denicija124a6fc2017-03-31 02:47:29 -0700138 [_vTexture replaceRegion:MTLRegionMake2D(0, 0, _chromaWidth, _chromaHeight)
139 mipmapLevel:0
Anders Carlssone5960ce2017-06-22 15:26:30 +0200140 withBytes:buffer.dataV
141 bytesPerRow:buffer.strideV];
denicija124a6fc2017-03-31 02:47:29 -0700142
denicija124a6fc2017-03-31 02:47:29 -0700143 return (_uTexture != nil) && (_yTexture != nil) && (_vTexture != nil);
144}
145
denicijad2088152017-04-28 02:14:54 -0700146- (void)uploadTexturesToRenderEncoder:(id<MTLRenderCommandEncoder>)renderEncoder {
147 [renderEncoder setFragmentTexture:_yTexture atIndex:0];
148 [renderEncoder setFragmentTexture:_uTexture atIndex:1];
149 [renderEncoder setFragmentTexture:_vTexture atIndex:2];
150}
151
denicija124a6fc2017-03-31 02:47:29 -0700152@end