| // | |
| // Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| // Stream.cpp: Implements the egl::Stream class, representing the stream | |
| // where frames are streamed in. Implements EGLStreanKHR. | |
| #include "libANGLE/Stream.h" | |
| #include <EGL/eglext.h> | |
| #include <platform/Platform.h> | |
| #include "common/debug.h" | |
| #include "common/mathutil.h" | |
| #include "common/platform.h" | |
| #include "common/utilities.h" | |
| #include "libANGLE/Context.h" | |
| #include "libANGLE/Display.h" | |
| #include "libANGLE/renderer/DisplayImpl.h" | |
| #include "libANGLE/renderer/StreamProducerImpl.h" | |
| namespace egl | |
| { | |
| Stream::Stream(Display *display, const AttributeMap &attribs) | |
| : mLabel(nullptr), | |
| mDisplay(display), | |
| mProducerImplementation(nullptr), | |
| mState(EGL_STREAM_STATE_CREATED_KHR), | |
| mProducerFrame(0), | |
| mConsumerFrame(0), | |
| mConsumerLatency(attribs.getAsInt(EGL_CONSUMER_LATENCY_USEC_KHR, 0)), | |
| mConsumerAcquireTimeout(attribs.getAsInt(EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0)), | |
| mPlaneCount(0), | |
| mConsumerType(ConsumerType::NoConsumer), | |
| mProducerType(ProducerType::NoProducer) | |
| { | |
| for (auto &plane : mPlanes) | |
| { | |
| plane.textureUnit = -1; | |
| plane.texture = nullptr; | |
| } | |
| } | |
| Stream::~Stream() | |
| { | |
| SafeDelete(mProducerImplementation); | |
| for (auto &plane : mPlanes) | |
| { | |
| if (plane.texture != nullptr) | |
| { | |
| plane.texture->releaseStream(); | |
| } | |
| } | |
| } | |
| void Stream::setLabel(EGLLabelKHR label) | |
| { | |
| mLabel = label; | |
| } | |
| EGLLabelKHR Stream::getLabel() const | |
| { | |
| return mLabel; | |
| } | |
| void Stream::setConsumerLatency(EGLint latency) | |
| { | |
| mConsumerLatency = latency; | |
| } | |
| EGLint Stream::getConsumerLatency() const | |
| { | |
| return mConsumerLatency; | |
| } | |
| EGLuint64KHR Stream::getProducerFrame() const | |
| { | |
| return mProducerFrame; | |
| } | |
| EGLuint64KHR Stream::getConsumerFrame() const | |
| { | |
| return mConsumerFrame; | |
| } | |
| EGLenum Stream::getState() const | |
| { | |
| return mState; | |
| } | |
| void Stream::setConsumerAcquireTimeout(EGLint timeout) | |
| { | |
| mConsumerAcquireTimeout = timeout; | |
| } | |
| EGLint Stream::getConsumerAcquireTimeout() const | |
| { | |
| return mConsumerAcquireTimeout; | |
| } | |
| Stream::ProducerType Stream::getProducerType() const | |
| { | |
| return mProducerType; | |
| } | |
| Stream::ConsumerType Stream::getConsumerType() const | |
| { | |
| return mConsumerType; | |
| } | |
| EGLint Stream::getPlaneCount() const | |
| { | |
| return mPlaneCount; | |
| } | |
| rx::StreamProducerImpl *Stream::getImplementation() | |
| { | |
| return mProducerImplementation; | |
| } | |
| Error Stream::createConsumerGLTextureExternal(const AttributeMap &attributes, gl::Context *context) | |
| { | |
| ASSERT(mState == EGL_STREAM_STATE_CREATED_KHR); | |
| ASSERT(mConsumerType == ConsumerType::NoConsumer); | |
| ASSERT(mProducerType == ProducerType::NoProducer); | |
| ASSERT(context != nullptr); | |
| const auto &glState = context->getGLState(); | |
| EGLenum bufferType = attributes.getAsInt(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER); | |
| if (bufferType == EGL_RGB_BUFFER) | |
| { | |
| mPlanes[0].texture = glState.getTargetTexture(gl::TextureType::External); | |
| ASSERT(mPlanes[0].texture != nullptr); | |
| mPlanes[0].texture->bindStream(this); | |
| mConsumerType = ConsumerType::GLTextureRGB; | |
| mPlaneCount = 1; | |
| } | |
| else | |
| { | |
| mPlaneCount = attributes.getAsInt(EGL_YUV_NUMBER_OF_PLANES_EXT, 2); | |
| ASSERT(mPlaneCount <= 3); | |
| for (EGLint i = 0; i < mPlaneCount; i++) | |
| { | |
| // Fetch all the textures | |
| mPlanes[i].textureUnit = attributes.getAsInt(EGL_YUV_PLANE0_TEXTURE_UNIT_NV + i, -1); | |
| if (mPlanes[i].textureUnit != EGL_NONE) | |
| { | |
| mPlanes[i].texture = | |
| glState.getSamplerTexture(mPlanes[i].textureUnit, gl::TextureType::External); | |
| ASSERT(mPlanes[i].texture != nullptr); | |
| } | |
| } | |
| // Bind them to the stream | |
| for (EGLint i = 0; i < mPlaneCount; i++) | |
| { | |
| if (mPlanes[i].textureUnit != EGL_NONE) | |
| { | |
| mPlanes[i].texture->bindStream(this); | |
| } | |
| } | |
| mConsumerType = ConsumerType::GLTextureYUV; | |
| } | |
| mContext = context; | |
| mState = EGL_STREAM_STATE_CONNECTING_KHR; | |
| return NoError(); | |
| } | |
| Error Stream::createProducerD3D11Texture(const AttributeMap &attributes) | |
| { | |
| ASSERT(mState == EGL_STREAM_STATE_CONNECTING_KHR); | |
| ASSERT(mConsumerType == ConsumerType::GLTextureRGB || | |
| mConsumerType == ConsumerType::GLTextureYUV); | |
| ASSERT(mProducerType == ProducerType::NoProducer); | |
| mProducerImplementation = | |
| mDisplay->getImplementation()->createStreamProducerD3DTexture(mConsumerType, attributes); | |
| mProducerType = ProducerType::D3D11Texture; | |
| mState = EGL_STREAM_STATE_EMPTY_KHR; | |
| return NoError(); | |
| } | |
| // Called when the consumer of this stream starts using the stream | |
| Error Stream::consumerAcquire(const gl::Context *context) | |
| { | |
| ASSERT(mState == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR || | |
| mState == EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR); | |
| ASSERT(mConsumerType == ConsumerType::GLTextureRGB || | |
| mConsumerType == ConsumerType::GLTextureYUV); | |
| ASSERT(mProducerType == ProducerType::D3D11Texture); | |
| mState = EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR; | |
| mConsumerFrame++; | |
| // Bind the planes to the gl textures | |
| for (int i = 0; i < mPlaneCount; i++) | |
| { | |
| if (mPlanes[i].texture != nullptr) | |
| { | |
| ANGLE_TRY(mPlanes[i].texture->acquireImageFromStream( | |
| context, mProducerImplementation->getGLFrameDescription(i))); | |
| } | |
| } | |
| return NoError(); | |
| } | |
| Error Stream::consumerRelease(const gl::Context *context) | |
| { | |
| ASSERT(mState == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR || | |
| mState == EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR); | |
| ASSERT(mConsumerType == ConsumerType::GLTextureRGB || | |
| mConsumerType == ConsumerType::GLTextureYUV); | |
| ASSERT(mProducerType == ProducerType::D3D11Texture); | |
| // Release the images | |
| for (int i = 0; i < mPlaneCount; i++) | |
| { | |
| if (mPlanes[i].texture != nullptr) | |
| { | |
| ANGLE_TRY(mPlanes[i].texture->releaseImageFromStream(context)); | |
| } | |
| } | |
| return NoError(); | |
| } | |
| bool Stream::isConsumerBoundToContext(const gl::Context *context) const | |
| { | |
| ASSERT(context != nullptr); | |
| return (context == mContext); | |
| } | |
| Error Stream::validateD3D11Texture(void *texture, const AttributeMap &attributes) const | |
| { | |
| ASSERT(mConsumerType == ConsumerType::GLTextureRGB || | |
| mConsumerType == ConsumerType::GLTextureYUV); | |
| ASSERT(mProducerType == ProducerType::D3D11Texture); | |
| ASSERT(mProducerImplementation != nullptr); | |
| return mProducerImplementation->validateD3DTexture(texture, attributes); | |
| } | |
| Error Stream::postD3D11Texture(void *texture, const AttributeMap &attributes) | |
| { | |
| ASSERT(mConsumerType == ConsumerType::GLTextureRGB || | |
| mConsumerType == ConsumerType::GLTextureYUV); | |
| ASSERT(mProducerType == ProducerType::D3D11Texture); | |
| mProducerImplementation->postD3DTexture(texture, attributes); | |
| mProducerFrame++; | |
| mState = EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR; | |
| return NoError(); | |
| } | |
| // This is called when a texture object associated with this stream is destroyed. Even if multiple | |
| // textures are bound, one being destroyed invalidates the stream, so all the remaining textures | |
| // will be released and the stream will be invalidated. | |
| void Stream::releaseTextures() | |
| { | |
| for (auto &plane : mPlanes) | |
| { | |
| if (plane.texture != nullptr) | |
| { | |
| plane.texture->releaseStream(); | |
| plane.texture = nullptr; | |
| } | |
| } | |
| mConsumerType = ConsumerType::NoConsumer; | |
| mProducerType = ProducerType::NoProducer; | |
| mState = EGL_STREAM_STATE_DISCONNECTED_KHR; | |
| } | |
| } // namespace egl |