blob: 668b9aed13dd8dbc1c6de9df489644516685782e [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"
12
13#import <Metal/Metal.h>
14#import <MetalKit/MetalKit.h>
15
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020016#import "base/RTCI420Buffer.h"
17#import "base/RTCLogging.h"
18#import "base/RTCVideoFrame.h"
19#import "base/RTCVideoFrameBuffer.h"
denicija124a6fc2017-03-31 02:47:29 -070020
denicijad2088152017-04-28 02:14:54 -070021#import "RTCMTLRenderer+Private.h"
denicija124a6fc2017-03-31 02:47:29 -070022
denicija124a6fc2017-03-31 02:47:29 -070023static NSString *const shaderSource = MTL_STRINGIFY(
Peter Hanspers1c62b982018-05-03 14:06:04 +020024 using namespace metal;
25
26 typedef struct {
denicija124a6fc2017-03-31 02:47:29 -070027 packed_float2 position;
28 packed_float2 texcoord;
29 } Vertex;
30
31 typedef struct {
32 float4 position[[position]];
33 float2 texcoord;
34 } Varyings;
35
36 vertex Varyings vertexPassthrough(device Vertex * verticies[[buffer(0)]],
37 unsigned int vid[[vertex_id]]) {
38 Varyings out;
39 device Vertex &v = verticies[vid];
40 out.position = float4(float2(v.position), 0.0, 1.0);
41 out.texcoord = v.texcoord;
42
43 return out;
44 }
45
46 fragment half4 fragmentColorConversion(
47 Varyings in[[stage_in]], texture2d<float, access::sample> textureY[[texture(0)]],
48 texture2d<float, access::sample> textureU[[texture(1)]],
49 texture2d<float, access::sample> textureV[[texture(2)]]) {
50 constexpr sampler s(address::clamp_to_edge, filter::linear);
51 float y;
52 float u;
53 float v;
54 float r;
55 float g;
56 float b;
57 // Conversion for YUV to rgb from http://www.fourcc.org/fccyvrgb.php
58 y = textureY.sample(s, in.texcoord).r;
59 u = textureU.sample(s, in.texcoord).r;
60 v = textureV.sample(s, in.texcoord).r;
61 u = u - 0.5;
62 v = v - 0.5;
63 r = y + 1.403 * v;
64 g = y - 0.344 * u - 0.714 * v;
65 b = y + 1.770 * u;
66
67 float4 out = float4(r, g, b, 1.0);
68
69 return half4(out);
70 });
71
denicija124a6fc2017-03-31 02:47:29 -070072@implementation RTCMTLI420Renderer {
denicija124a6fc2017-03-31 02:47:29 -070073 // Textures.
74 id<MTLTexture> _yTexture;
75 id<MTLTexture> _uTexture;
76 id<MTLTexture> _vTexture;
77
78 MTLTextureDescriptor *_descriptor;
79 MTLTextureDescriptor *_chromaDescriptor;
80
81 int _width;
82 int _height;
83 int _chromaWidth;
84 int _chromaHeight;
denicija124a6fc2017-03-31 02:47:29 -070085}
86
denicijad2088152017-04-28 02:14:54 -070087#pragma mark - Virtual
denicija124a6fc2017-03-31 02:47:29 -070088
denicijad2088152017-04-28 02:14:54 -070089- (NSString *)shaderSource {
90 return shaderSource;
denicija124a6fc2017-03-31 02:47:29 -070091}
92
Peter Hanspers7af087a2018-06-12 14:14:48 +020093- (void)getWidth:(nonnull int *)width
94 height:(nonnull int *)height
95 cropWidth:(nonnull int *)cropWidth
96 cropHeight:(nonnull int *)cropHeight
97 cropX:(nonnull int *)cropX
98 cropY:(nonnull int *)cropY
99 ofFrame:(nonnull RTCVideoFrame *)frame {
100 *width = frame.width;
101 *height = frame.height;
102 *cropWidth = frame.width;
103 *cropHeight = frame.height;
104 *cropX = 0;
105 *cropY = 0;
106}
107
denicija124a6fc2017-03-31 02:47:29 -0700108- (BOOL)setupTexturesForFrame:(nonnull RTCVideoFrame *)frame {
Peter Hanspers5daaf7d2018-06-01 10:34:37 +0200109 if (![super setupTexturesForFrame:frame]) {
110 return NO;
111 }
denicija124a6fc2017-03-31 02:47:29 -0700112
denicijad2088152017-04-28 02:14:54 -0700113 id<MTLDevice> device = [self currentMetalDevice];
114 if (!device) {
115 return NO;
116 }
117
Anders Carlssone5960ce2017-06-22 15:26:30 +0200118 id<RTCI420Buffer> buffer = [frame.buffer toI420];
119
denicijad2088152017-04-28 02:14:54 -0700120 // Luma (y) texture.
denicija124a6fc2017-03-31 02:47:29 -0700121 if (!_descriptor || (_width != frame.width && _height != frame.height)) {
122 _width = frame.width;
123 _height = frame.height;
124 _descriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Unorm
125 width:_width
126 height:_height
127 mipmapped:NO];
128 _descriptor.usage = MTLTextureUsageShaderRead;
denicijad2088152017-04-28 02:14:54 -0700129 _yTexture = [device newTextureWithDescriptor:_descriptor];
denicija124a6fc2017-03-31 02:47:29 -0700130 }
131
132 // Chroma (u,v) textures
133 [_yTexture replaceRegion:MTLRegionMake2D(0, 0, _width, _height)
134 mipmapLevel:0
Anders Carlssone5960ce2017-06-22 15:26:30 +0200135 withBytes:buffer.dataY
136 bytesPerRow:buffer.strideY];
denicija124a6fc2017-03-31 02:47:29 -0700137
138 if (!_chromaDescriptor ||
139 (_chromaWidth != frame.width / 2 && _chromaHeight != frame.height / 2)) {
140 _chromaWidth = frame.width / 2;
141 _chromaHeight = frame.height / 2;
142 _chromaDescriptor =
143 [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Unorm
144 width:_chromaWidth
145 height:_chromaHeight
146 mipmapped:NO];
147 _chromaDescriptor.usage = MTLTextureUsageShaderRead;
denicijad2088152017-04-28 02:14:54 -0700148 _uTexture = [device newTextureWithDescriptor:_chromaDescriptor];
149 _vTexture = [device newTextureWithDescriptor:_chromaDescriptor];
denicija124a6fc2017-03-31 02:47:29 -0700150 }
151
152 [_uTexture replaceRegion:MTLRegionMake2D(0, 0, _chromaWidth, _chromaHeight)
153 mipmapLevel:0
Anders Carlssone5960ce2017-06-22 15:26:30 +0200154 withBytes:buffer.dataU
155 bytesPerRow:buffer.strideU];
denicija124a6fc2017-03-31 02:47:29 -0700156 [_vTexture replaceRegion:MTLRegionMake2D(0, 0, _chromaWidth, _chromaHeight)
157 mipmapLevel:0
Anders Carlssone5960ce2017-06-22 15:26:30 +0200158 withBytes:buffer.dataV
159 bytesPerRow:buffer.strideV];
denicija124a6fc2017-03-31 02:47:29 -0700160
denicija124a6fc2017-03-31 02:47:29 -0700161 return (_uTexture != nil) && (_yTexture != nil) && (_vTexture != nil);
162}
163
denicijad2088152017-04-28 02:14:54 -0700164- (void)uploadTexturesToRenderEncoder:(id<MTLRenderCommandEncoder>)renderEncoder {
165 [renderEncoder setFragmentTexture:_yTexture atIndex:0];
166 [renderEncoder setFragmentTexture:_uTexture atIndex:1];
167 [renderEncoder setFragmentTexture:_vTexture atIndex:2];
168}
169
denicija124a6fc2017-03-31 02:47:29 -0700170@end