diff options
Diffstat (limited to 'gfx/angle/src/libANGLE/Stream.cpp')
-rwxr-xr-x | gfx/angle/src/libANGLE/Stream.cpp | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/gfx/angle/src/libANGLE/Stream.cpp b/gfx/angle/src/libANGLE/Stream.cpp new file mode 100755 index 000000000..8cf078c21 --- /dev/null +++ b/gfx/angle/src/libANGLE/Stream.cpp @@ -0,0 +1,271 @@ +// +// 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 <platform/Platform.h> +#include <EGL/eglext.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) + : 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::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_TEXTURE_EXTERNAL_OES); + 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_TEXTURE_EXTERNAL_OES); + 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 Error(EGL_SUCCESS); +} + +Error Stream::createProducerD3D11TextureNV12(const AttributeMap &attributes) +{ + ASSERT(mState == EGL_STREAM_STATE_CONNECTING_KHR); + ASSERT(mConsumerType == ConsumerType::GLTextureYUV); + ASSERT(mProducerType == ProducerType::NoProducer); + ASSERT(mPlaneCount == 2); + + mProducerImplementation = mDisplay->getImplementation()->createStreamProducerD3DTextureNV12( + mConsumerType, attributes); + mProducerType = ProducerType::D3D11TextureNV12; + mState = EGL_STREAM_STATE_EMPTY_KHR; + + return Error(EGL_SUCCESS); +} + +// Called when the consumer of this stream starts using the stream +Error Stream::consumerAcquire() +{ + 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::D3D11TextureNV12); + + 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) + { + mPlanes[i].texture->acquireImageFromStream( + mProducerImplementation->getGLFrameDescription(i)); + } + } + + return Error(EGL_SUCCESS); +} + +Error Stream::consumerRelease() +{ + 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::D3D11TextureNV12); + + // Release the images + for (int i = 0; i < mPlaneCount; i++) + { + if (mPlanes[i].texture != nullptr) + { + mPlanes[i].texture->releaseImageFromStream(); + } + } + + return Error(EGL_SUCCESS); +} + +bool Stream::isConsumerBoundToContext(const gl::Context *context) const +{ + ASSERT(context != nullptr); + return (context == mContext); +} + +Error Stream::validateD3D11NV12Texture(void *texture) const +{ + ASSERT(mConsumerType == ConsumerType::GLTextureRGB || + mConsumerType == ConsumerType::GLTextureYUV); + ASSERT(mProducerType == ProducerType::D3D11TextureNV12); + ASSERT(mProducerImplementation != nullptr); + + return mProducerImplementation->validateD3DNV12Texture(texture); +} + +Error Stream::postD3D11NV12Texture(void *texture, const AttributeMap &attributes) +{ + ASSERT(mConsumerType == ConsumerType::GLTextureRGB || + mConsumerType == ConsumerType::GLTextureYUV); + ASSERT(mProducerType == ProducerType::D3D11TextureNV12); + + mProducerImplementation->postD3DNV12Texture(texture, attributes); + mProducerFrame++; + + mState = EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR; + + return Error(EGL_SUCCESS); +} + +// 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 |