denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 1 | /* |
| 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 Carlsson | e5960ce | 2017-06-22 15:26:30 +0200 | [diff] [blame] | 12 | #import "WebRTC/RTCVideoFrameBuffer.h" |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 13 | |
| 14 | #import <Metal/Metal.h> |
| 15 | #import <MetalKit/MetalKit.h> |
| 16 | |
| 17 | #import "WebRTC/RTCLogging.h" |
| 18 | #import "WebRTC/RTCVideoFrame.h" |
| 19 | |
denicija | d208815 | 2017-04-28 02:14:54 -0700 | [diff] [blame] | 20 | #import "RTCMTLRenderer+Private.h" |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 21 | |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 22 | static NSString *const shaderSource = MTL_STRINGIFY( |
Peter Hanspers | 1c62b98 | 2018-05-03 14:06:04 +0200 | [diff] [blame] | 23 | using namespace metal; |
| 24 | |
| 25 | typedef struct { |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 26 | 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 | |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 71 | @implementation RTCMTLI420Renderer { |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 72 | // 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; |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 84 | } |
| 85 | |
denicija | d208815 | 2017-04-28 02:14:54 -0700 | [diff] [blame] | 86 | #pragma mark - Virtual |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 87 | |
denicija | d208815 | 2017-04-28 02:14:54 -0700 | [diff] [blame] | 88 | - (NSString *)shaderSource { |
| 89 | return shaderSource; |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 90 | } |
| 91 | |
Peter Hanspers | 7af087a | 2018-06-12 14:14:48 +0200 | [diff] [blame] | 92 | - (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 | |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 107 | - (BOOL)setupTexturesForFrame:(nonnull RTCVideoFrame *)frame { |
Peter Hanspers | 5daaf7d | 2018-06-01 10:34:37 +0200 | [diff] [blame] | 108 | if (![super setupTexturesForFrame:frame]) { |
| 109 | return NO; |
| 110 | } |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 111 | |
denicija | d208815 | 2017-04-28 02:14:54 -0700 | [diff] [blame] | 112 | id<MTLDevice> device = [self currentMetalDevice]; |
| 113 | if (!device) { |
| 114 | return NO; |
| 115 | } |
| 116 | |
Anders Carlsson | e5960ce | 2017-06-22 15:26:30 +0200 | [diff] [blame] | 117 | id<RTCI420Buffer> buffer = [frame.buffer toI420]; |
| 118 | |
denicija | d208815 | 2017-04-28 02:14:54 -0700 | [diff] [blame] | 119 | // Luma (y) texture. |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 120 | 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; |
denicija | d208815 | 2017-04-28 02:14:54 -0700 | [diff] [blame] | 128 | _yTexture = [device newTextureWithDescriptor:_descriptor]; |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 129 | } |
| 130 | |
| 131 | // Chroma (u,v) textures |
| 132 | [_yTexture replaceRegion:MTLRegionMake2D(0, 0, _width, _height) |
| 133 | mipmapLevel:0 |
Anders Carlsson | e5960ce | 2017-06-22 15:26:30 +0200 | [diff] [blame] | 134 | withBytes:buffer.dataY |
| 135 | bytesPerRow:buffer.strideY]; |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 136 | |
| 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; |
denicija | d208815 | 2017-04-28 02:14:54 -0700 | [diff] [blame] | 147 | _uTexture = [device newTextureWithDescriptor:_chromaDescriptor]; |
| 148 | _vTexture = [device newTextureWithDescriptor:_chromaDescriptor]; |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 149 | } |
| 150 | |
| 151 | [_uTexture replaceRegion:MTLRegionMake2D(0, 0, _chromaWidth, _chromaHeight) |
| 152 | mipmapLevel:0 |
Anders Carlsson | e5960ce | 2017-06-22 15:26:30 +0200 | [diff] [blame] | 153 | withBytes:buffer.dataU |
| 154 | bytesPerRow:buffer.strideU]; |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 155 | [_vTexture replaceRegion:MTLRegionMake2D(0, 0, _chromaWidth, _chromaHeight) |
| 156 | mipmapLevel:0 |
Anders Carlsson | e5960ce | 2017-06-22 15:26:30 +0200 | [diff] [blame] | 157 | withBytes:buffer.dataV |
| 158 | bytesPerRow:buffer.strideV]; |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 159 | |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 160 | return (_uTexture != nil) && (_yTexture != nil) && (_vTexture != nil); |
| 161 | } |
| 162 | |
denicija | d208815 | 2017-04-28 02:14:54 -0700 | [diff] [blame] | 163 | - (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 | |
denicija | 124a6fc | 2017-03-31 02:47:29 -0700 | [diff] [blame] | 169 | @end |