Stream.cpp (7909B)
1 // 2 // Copyright 2016 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // Stream.cpp: Implements the egl::Stream class, representing the stream 8 // where frames are streamed in. Implements EGLStreanKHR. 9 10 #include "libANGLE/Stream.h" 11 12 #include <EGL/eglext.h> 13 #include <platform/PlatformMethods.h> 14 15 #include "common/debug.h" 16 #include "common/mathutil.h" 17 #include "common/platform.h" 18 #include "common/utilities.h" 19 #include "libANGLE/Context.h" 20 #include "libANGLE/Display.h" 21 #include "libANGLE/renderer/DisplayImpl.h" 22 #include "libANGLE/renderer/StreamProducerImpl.h" 23 24 namespace egl 25 { 26 27 Stream::Stream(Display *display, const AttributeMap &attribs) 28 : mLabel(nullptr), 29 mDisplay(display), 30 mProducerImplementation(nullptr), 31 mState(EGL_STREAM_STATE_CREATED_KHR), 32 mProducerFrame(0), 33 mConsumerFrame(0), 34 mConsumerLatency(attribs.getAsInt(EGL_CONSUMER_LATENCY_USEC_KHR, 0)), 35 mConsumerAcquireTimeout(attribs.getAsInt(EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0)), 36 mPlaneCount(0), 37 mConsumerType(ConsumerType::NoConsumer), 38 mProducerType(ProducerType::NoProducer) 39 { 40 for (auto &plane : mPlanes) 41 { 42 plane.textureUnit = -1; 43 plane.texture = nullptr; 44 } 45 } 46 47 Stream::~Stream() 48 { 49 SafeDelete(mProducerImplementation); 50 for (auto &plane : mPlanes) 51 { 52 if (plane.texture != nullptr) 53 { 54 plane.texture->releaseStream(); 55 } 56 } 57 } 58 59 void Stream::setLabel(EGLLabelKHR label) 60 { 61 mLabel = label; 62 } 63 64 EGLLabelKHR Stream::getLabel() const 65 { 66 return mLabel; 67 } 68 69 void Stream::setConsumerLatency(EGLint latency) 70 { 71 mConsumerLatency = latency; 72 } 73 74 EGLint Stream::getConsumerLatency() const 75 { 76 return mConsumerLatency; 77 } 78 79 EGLuint64KHR Stream::getProducerFrame() const 80 { 81 return mProducerFrame; 82 } 83 84 EGLuint64KHR Stream::getConsumerFrame() const 85 { 86 return mConsumerFrame; 87 } 88 89 EGLenum Stream::getState() const 90 { 91 return mState; 92 } 93 94 void Stream::setConsumerAcquireTimeout(EGLint timeout) 95 { 96 mConsumerAcquireTimeout = timeout; 97 } 98 99 EGLint Stream::getConsumerAcquireTimeout() const 100 { 101 return mConsumerAcquireTimeout; 102 } 103 104 Stream::ProducerType Stream::getProducerType() const 105 { 106 return mProducerType; 107 } 108 109 Stream::ConsumerType Stream::getConsumerType() const 110 { 111 return mConsumerType; 112 } 113 114 EGLint Stream::getPlaneCount() const 115 { 116 return mPlaneCount; 117 } 118 119 rx::StreamProducerImpl *Stream::getImplementation() 120 { 121 return mProducerImplementation; 122 } 123 124 Error Stream::createConsumerGLTextureExternal(const AttributeMap &attributes, gl::Context *context) 125 { 126 ASSERT(mState == EGL_STREAM_STATE_CREATED_KHR); 127 ASSERT(mConsumerType == ConsumerType::NoConsumer); 128 ASSERT(mProducerType == ProducerType::NoProducer); 129 ASSERT(context != nullptr); 130 131 const auto &glState = context->getState(); 132 EGLenum bufferType = attributes.getAsInt(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER); 133 if (bufferType == EGL_RGB_BUFFER) 134 { 135 mPlanes[0].texture = glState.getTargetTexture(gl::TextureType::External); 136 ASSERT(mPlanes[0].texture != nullptr); 137 mPlanes[0].texture->bindStream(this); 138 mConsumerType = ConsumerType::GLTextureRGB; 139 mPlaneCount = 1; 140 } 141 else 142 { 143 mPlaneCount = attributes.getAsInt(EGL_YUV_NUMBER_OF_PLANES_EXT, 2); 144 ASSERT(mPlaneCount <= 3); 145 for (EGLint i = 0; i < mPlaneCount; i++) 146 { 147 // Fetch all the textures 148 mPlanes[i].textureUnit = attributes.getAsInt(EGL_YUV_PLANE0_TEXTURE_UNIT_NV + i, -1); 149 if (mPlanes[i].textureUnit != EGL_NONE) 150 { 151 mPlanes[i].texture = 152 glState.getSamplerTexture(mPlanes[i].textureUnit, gl::TextureType::External); 153 ASSERT(mPlanes[i].texture != nullptr); 154 } 155 } 156 157 // Bind them to the stream 158 for (EGLint i = 0; i < mPlaneCount; i++) 159 { 160 if (mPlanes[i].textureUnit != EGL_NONE) 161 { 162 mPlanes[i].texture->bindStream(this); 163 } 164 } 165 mConsumerType = ConsumerType::GLTextureYUV; 166 } 167 168 mContext = context; 169 mState = EGL_STREAM_STATE_CONNECTING_KHR; 170 171 return NoError(); 172 } 173 174 Error Stream::createProducerD3D11Texture(const AttributeMap &attributes) 175 { 176 ASSERT(mState == EGL_STREAM_STATE_CONNECTING_KHR); 177 ASSERT(mConsumerType == ConsumerType::GLTextureRGB || 178 mConsumerType == ConsumerType::GLTextureYUV); 179 ASSERT(mProducerType == ProducerType::NoProducer); 180 181 mProducerImplementation = 182 mDisplay->getImplementation()->createStreamProducerD3DTexture(mConsumerType, attributes); 183 mProducerType = ProducerType::D3D11Texture; 184 mState = EGL_STREAM_STATE_EMPTY_KHR; 185 186 return NoError(); 187 } 188 189 // Called when the consumer of this stream starts using the stream 190 Error Stream::consumerAcquire(const gl::Context *context) 191 { 192 ASSERT(mState == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR || 193 mState == EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR); 194 ASSERT(mConsumerType == ConsumerType::GLTextureRGB || 195 mConsumerType == ConsumerType::GLTextureYUV); 196 ASSERT(mProducerType == ProducerType::D3D11Texture); 197 198 mState = EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR; 199 mConsumerFrame++; 200 201 // Bind the planes to the gl textures 202 for (int i = 0; i < mPlaneCount; i++) 203 { 204 if (mPlanes[i].texture != nullptr) 205 { 206 ANGLE_TRY(ResultToEGL(mPlanes[i].texture->acquireImageFromStream( 207 context, mProducerImplementation->getGLFrameDescription(i)))); 208 } 209 } 210 211 return NoError(); 212 } 213 214 Error Stream::consumerRelease(const gl::Context *context) 215 { 216 ASSERT(mState == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR || 217 mState == EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR); 218 ASSERT(mConsumerType == ConsumerType::GLTextureRGB || 219 mConsumerType == ConsumerType::GLTextureYUV); 220 ASSERT(mProducerType == ProducerType::D3D11Texture); 221 222 // Release the images 223 for (int i = 0; i < mPlaneCount; i++) 224 { 225 if (mPlanes[i].texture != nullptr) 226 { 227 ANGLE_TRY(ResultToEGL(mPlanes[i].texture->releaseImageFromStream(context))); 228 } 229 } 230 231 return NoError(); 232 } 233 234 bool Stream::isConsumerBoundToContext(const gl::Context *context) const 235 { 236 ASSERT(context != nullptr); 237 return (context == mContext); 238 } 239 240 Error Stream::validateD3D11Texture(const void *texture, const AttributeMap &attributes) const 241 { 242 ASSERT(mConsumerType == ConsumerType::GLTextureRGB || 243 mConsumerType == ConsumerType::GLTextureYUV); 244 ASSERT(mProducerType == ProducerType::D3D11Texture); 245 ASSERT(mProducerImplementation != nullptr); 246 247 return mProducerImplementation->validateD3DTexture(texture, attributes); 248 } 249 250 Error Stream::postD3D11Texture(void *texture, const AttributeMap &attributes) 251 { 252 ASSERT(mConsumerType == ConsumerType::GLTextureRGB || 253 mConsumerType == ConsumerType::GLTextureYUV); 254 ASSERT(mProducerType == ProducerType::D3D11Texture); 255 256 mProducerImplementation->postD3DTexture(texture, attributes); 257 mProducerFrame++; 258 259 mState = EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR; 260 261 return NoError(); 262 } 263 264 // This is called when a texture object associated with this stream is destroyed. Even if multiple 265 // textures are bound, one being destroyed invalidates the stream, so all the remaining textures 266 // will be released and the stream will be invalidated. 267 void Stream::releaseTextures() 268 { 269 for (auto &plane : mPlanes) 270 { 271 if (plane.texture != nullptr) 272 { 273 plane.texture->releaseStream(); 274 plane.texture = nullptr; 275 } 276 } 277 mConsumerType = ConsumerType::NoConsumer; 278 mProducerType = ProducerType::NoProducer; 279 mState = EGL_STREAM_STATE_DISCONNECTED_KHR; 280 } 281 282 } // namespace egl