blob: 6cd7ff30557aec728cbc9745f3907392634f8012 [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
Kári Tristan Helgason93d4c102019-08-19 15:17:37 +020036 vertex Varyings vertexPassthrough(constant Vertex *verticies[[buffer(0)]],
denicija124a6fc2017-03-31 02:47:29 -070037 unsigned int vid[[vertex_id]]) {
38 Varyings out;
Kári Tristan Helgason93d4c102019-08-19 15:17:37 +020039 constant Vertex &v = verticies[vid];
denicija124a6fc2017-03-31 02:47:29 -070040 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(
Kári Tristan Helgason93d4c102019-08-19 15:17:37 +020047 Varyings in[[stage_in]],
48 texture2d<float, access::sample> textureY[[texture(0)]],
denicija124a6fc2017-03-31 02:47:29 -070049 texture2d<float, access::sample> textureU[[texture(1)]],
50 texture2d<float, access::sample> textureV[[texture(2)]]) {
51 constexpr sampler s(address::clamp_to_edge, filter::linear);
52 float y;
53 float u;
54 float v;
55 float r;
56 float g;
57 float b;
58 // Conversion for YUV to rgb from http://www.fourcc.org/fccyvrgb.php
59 y = textureY.sample(s, in.texcoord).r;
60 u = textureU.sample(s, in.texcoord).r;
61 v = textureV.sample(s, in.texcoord).r;
62 u = u - 0.5;
63 v = v - 0.5;
64 r = y + 1.403 * v;
65 g = y - 0.344 * u - 0.714 * v;
66 b = y + 1.770 * u;
67
68 float4 out = float4(r, g, b, 1.0);
69
70 return half4(out);
71 });
72
denicija124a6fc2017-03-31 02:47:29 -070073@implementation RTCMTLI420Renderer {
denicija124a6fc2017-03-31 02:47:29 -070074 // Textures.
75 id<MTLTexture> _yTexture;
76 id<MTLTexture> _uTexture;
77 id<MTLTexture> _vTexture;
78
79 MTLTextureDescriptor *_descriptor;
80 MTLTextureDescriptor *_chromaDescriptor;
81
82 int _width;
83 int _height;
84 int _chromaWidth;
85 int _chromaHeight;
denicija124a6fc2017-03-31 02:47:29 -070086}
87
denicijad2088152017-04-28 02:14:54 -070088#pragma mark - Virtual
denicija124a6fc2017-03-31 02:47:29 -070089
denicijad2088152017-04-28 02:14:54 -070090- (NSString *)shaderSource {
91 return shaderSource;
denicija124a6fc2017-03-31 02:47:29 -070092}
93
Peter Hanspers7af087a2018-06-12 14:14:48 +020094- (void)getWidth:(nonnull int *)width
95 height:(nonnull int *)height
96 cropWidth:(nonnull int *)cropWidth
97 cropHeight:(nonnull int *)cropHeight
98 cropX:(nonnull int *)cropX
99 cropY:(nonnull int *)cropY
100 ofFrame:(nonnull RTCVideoFrame *)frame {
101 *width = frame.width;
102 *height = frame.height;
103 *cropWidth = frame.width;
104 *cropHeight = frame.height;
105 *cropX = 0;
106 *cropY = 0;
107}
108
denicija124a6fc2017-03-31 02:47:29 -0700109- (BOOL)setupTexturesForFrame:(nonnull RTCVideoFrame *)frame {
Peter Hanspers5daaf7d2018-06-01 10:34:37 +0200110 if (![super setupTexturesForFrame:frame]) {
111 return NO;
112 }
denicija124a6fc2017-03-31 02:47:29 -0700113
denicijad2088152017-04-28 02:14:54 -0700114 id<MTLDevice> device = [self currentMetalDevice];
115 if (!device) {
116 return NO;
117 }
118
Anders Carlssone5960ce2017-06-22 15:26:30 +0200119 id<RTCI420Buffer> buffer = [frame.buffer toI420];
120
denicijad2088152017-04-28 02:14:54 -0700121 // Luma (y) texture.
Anders Carlsson48fcf942018-11-28 13:55:55 +0100122 if (!_descriptor || _width != frame.width || _height != frame.height) {
denicija124a6fc2017-03-31 02:47:29 -0700123 _width = frame.width;
124 _height = frame.height;
125 _descriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Unorm
126 width:_width
127 height:_height
128 mipmapped:NO];
129 _descriptor.usage = MTLTextureUsageShaderRead;
denicijad2088152017-04-28 02:14:54 -0700130 _yTexture = [device newTextureWithDescriptor:_descriptor];
denicija124a6fc2017-03-31 02:47:29 -0700131 }
132
133 // Chroma (u,v) textures
134 [_yTexture replaceRegion:MTLRegionMake2D(0, 0, _width, _height)
135 mipmapLevel:0
Anders Carlssone5960ce2017-06-22 15:26:30 +0200136 withBytes:buffer.dataY
137 bytesPerRow:buffer.strideY];
denicija124a6fc2017-03-31 02:47:29 -0700138
Anders Carlsson48fcf942018-11-28 13:55:55 +0100139 if (!_chromaDescriptor || _chromaWidth != frame.width / 2 || _chromaHeight != frame.height / 2) {
denicija124a6fc2017-03-31 02:47:29 -0700140 _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