| OLD | NEW |
| (Empty) |
| 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 "RTCI420TextureCache.h" | |
| 12 | |
| 13 #import "RTCShader+Private.h" | |
| 14 | |
| 15 #include <vector> | |
| 16 | |
| 17 // Two sets of 3 textures are used here, one for each of the Y, U and V planes.
Having two sets | |
| 18 // alleviates CPU blockage in the event that the GPU is asked to render to a tex
ture that is already | |
| 19 // in use. | |
| 20 static const GLsizei kNumTextureSets = 2; | |
| 21 static const GLsizei kNumTexturesPerSet = 3; | |
| 22 static const GLsizei kNumTextures = kNumTexturesPerSet * kNumTextureSets; | |
| 23 | |
| 24 @implementation RTCI420TextureCache { | |
| 25 BOOL _hasUnpackRowLength; | |
| 26 GLint _currentTextureSet; | |
| 27 // Handles for OpenGL constructs. | |
| 28 GLuint _textures[kNumTextures]; | |
| 29 // Used to create a non-padded plane for GPU upload when we receive padded fra
mes. | |
| 30 std::vector<uint8_t> _planeBuffer; | |
| 31 } | |
| 32 | |
| 33 - (GLuint)yTexture { | |
| 34 return _textures[_currentTextureSet * kNumTexturesPerSet]; | |
| 35 } | |
| 36 | |
| 37 - (GLuint)uTexture { | |
| 38 return _textures[_currentTextureSet * kNumTexturesPerSet + 1]; | |
| 39 } | |
| 40 | |
| 41 - (GLuint)vTexture { | |
| 42 return _textures[_currentTextureSet * kNumTexturesPerSet + 2]; | |
| 43 } | |
| 44 | |
| 45 - (instancetype)initWithContext:(GlContextType *)context { | |
| 46 if (self = [super init]) { | |
| 47 #if TARGET_OS_IPHONE | |
| 48 _hasUnpackRowLength = (context.API == kEAGLRenderingAPIOpenGLES3); | |
| 49 #else | |
| 50 _hasUnpackRowLength = YES; | |
| 51 #endif | |
| 52 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |
| 53 | |
| 54 [self setupTextures]; | |
| 55 } | |
| 56 return self; | |
| 57 } | |
| 58 | |
| 59 - (void)dealloc { | |
| 60 glDeleteTextures(kNumTextures, _textures); | |
| 61 } | |
| 62 | |
| 63 - (void)setupTextures { | |
| 64 glGenTextures(kNumTextures, _textures); | |
| 65 // Set parameters for each of the textures we created. | |
| 66 for (GLsizei i = 0; i < kNumTextures; i++) { | |
| 67 glBindTexture(GL_TEXTURE_2D, _textures[i]); | |
| 68 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| 69 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| 70 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| 71 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| 72 } | |
| 73 } | |
| 74 | |
| 75 - (void)uploadPlane:(const uint8_t *)plane | |
| 76 texture:(GLuint)texture | |
| 77 width:(size_t)width | |
| 78 height:(size_t)height | |
| 79 stride:(int32_t)stride { | |
| 80 glBindTexture(GL_TEXTURE_2D, texture); | |
| 81 | |
| 82 const uint8_t *uploadPlane = plane; | |
| 83 if ((size_t)stride != width) { | |
| 84 if (_hasUnpackRowLength) { | |
| 85 // GLES3 allows us to specify stride. | |
| 86 glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); | |
| 87 glTexImage2D(GL_TEXTURE_2D, | |
| 88 0, | |
| 89 RTC_PIXEL_FORMAT, | |
| 90 static_cast<GLsizei>(width), | |
| 91 static_cast<GLsizei>(height), | |
| 92 0, | |
| 93 RTC_PIXEL_FORMAT, | |
| 94 GL_UNSIGNED_BYTE, | |
| 95 uploadPlane); | |
| 96 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | |
| 97 return; | |
| 98 } else { | |
| 99 // Make an unpadded copy and upload that instead. Quick profiling showed | |
| 100 // that this is faster than uploading row by row using glTexSubImage2D. | |
| 101 uint8_t *unpaddedPlane = _planeBuffer.data(); | |
| 102 for (size_t y = 0; y < height; ++y) { | |
| 103 memcpy(unpaddedPlane + y * width, plane + y * stride, width); | |
| 104 } | |
| 105 uploadPlane = unpaddedPlane; | |
| 106 } | |
| 107 } | |
| 108 glTexImage2D(GL_TEXTURE_2D, | |
| 109 0, | |
| 110 RTC_PIXEL_FORMAT, | |
| 111 static_cast<GLsizei>(width), | |
| 112 static_cast<GLsizei>(height), | |
| 113 0, | |
| 114 RTC_PIXEL_FORMAT, | |
| 115 GL_UNSIGNED_BYTE, | |
| 116 uploadPlane); | |
| 117 } | |
| 118 | |
| 119 - (void)uploadFrameToTextures:(RTCVideoFrame *)frame { | |
| 120 _currentTextureSet = (_currentTextureSet + 1) % kNumTextureSets; | |
| 121 | |
| 122 const int chromaWidth = (frame.width + 1) / 2; | |
| 123 const int chromaHeight = (frame.height + 1) / 2; | |
| 124 if (frame.strideY != frame.width || | |
| 125 frame.strideU != chromaWidth || | |
| 126 frame.strideV != chromaWidth) { | |
| 127 _planeBuffer.resize(frame.width * frame.height); | |
| 128 } | |
| 129 | |
| 130 [self uploadPlane:frame.dataY | |
| 131 texture:self.yTexture | |
| 132 width:frame.width | |
| 133 height:frame.height | |
| 134 stride:frame.strideY]; | |
| 135 | |
| 136 [self uploadPlane:frame.dataU | |
| 137 texture:self.uTexture | |
| 138 width:chromaWidth | |
| 139 height:chromaHeight | |
| 140 stride:frame.strideU]; | |
| 141 | |
| 142 [self uploadPlane:frame.dataV | |
| 143 texture:self.vTexture | |
| 144 width:chromaWidth | |
| 145 height:chromaHeight | |
| 146 stride:frame.strideV]; | |
| 147 } | |
| 148 | |
| 149 @end | |
| OLD | NEW |