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/Platform.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
Stream(Display * display,const AttributeMap & attribs)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
~Stream()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
setLabel(EGLLabelKHR label)59 void Stream::setLabel(EGLLabelKHR label)
60 {
61 mLabel = label;
62 }
63
getLabel() const64 EGLLabelKHR Stream::getLabel() const
65 {
66 return mLabel;
67 }
68
setConsumerLatency(EGLint latency)69 void Stream::setConsumerLatency(EGLint latency)
70 {
71 mConsumerLatency = latency;
72 }
73
getConsumerLatency() const74 EGLint Stream::getConsumerLatency() const
75 {
76 return mConsumerLatency;
77 }
78
getProducerFrame() const79 EGLuint64KHR Stream::getProducerFrame() const
80 {
81 return mProducerFrame;
82 }
83
getConsumerFrame() const84 EGLuint64KHR Stream::getConsumerFrame() const
85 {
86 return mConsumerFrame;
87 }
88
getState() const89 EGLenum Stream::getState() const
90 {
91 return mState;
92 }
93
setConsumerAcquireTimeout(EGLint timeout)94 void Stream::setConsumerAcquireTimeout(EGLint timeout)
95 {
96 mConsumerAcquireTimeout = timeout;
97 }
98
getConsumerAcquireTimeout() const99 EGLint Stream::getConsumerAcquireTimeout() const
100 {
101 return mConsumerAcquireTimeout;
102 }
103
getProducerType() const104 Stream::ProducerType Stream::getProducerType() const
105 {
106 return mProducerType;
107 }
108
getConsumerType() const109 Stream::ConsumerType Stream::getConsumerType() const
110 {
111 return mConsumerType;
112 }
113
getPlaneCount() const114 EGLint Stream::getPlaneCount() const
115 {
116 return mPlaneCount;
117 }
118
getImplementation()119 rx::StreamProducerImpl *Stream::getImplementation()
120 {
121 return mProducerImplementation;
122 }
123
createConsumerGLTextureExternal(const AttributeMap & attributes,gl::Context * context)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
createProducerD3D11Texture(const AttributeMap & attributes)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
consumerAcquire(const gl::Context * context)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
consumerRelease(const gl::Context * context)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
isConsumerBoundToContext(const gl::Context * context) const234 bool Stream::isConsumerBoundToContext(const gl::Context *context) const
235 {
236 ASSERT(context != nullptr);
237 return (context == mContext);
238 }
239
validateD3D11Texture(const void * texture,const AttributeMap & attributes) const240 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
postD3D11Texture(void * texture,const AttributeMap & attributes)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.
releaseTextures()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
283