• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2015 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 // Image.cpp: Implements the egl::Image class representing the EGLimage object.
8 
9 #include "libANGLE/Image.h"
10 
11 #include "common/debug.h"
12 #include "common/utilities.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/Renderbuffer.h"
15 #include "libANGLE/Texture.h"
16 #include "libANGLE/angletypes.h"
17 #include "libANGLE/formatutils.h"
18 #include "libANGLE/renderer/EGLImplFactory.h"
19 #include "libANGLE/renderer/ImageImpl.h"
20 
21 namespace egl
22 {
23 
24 namespace
25 {
GetImageIndex(EGLenum eglTarget,const egl::AttributeMap & attribs)26 gl::ImageIndex GetImageIndex(EGLenum eglTarget, const egl::AttributeMap &attribs)
27 {
28     if (!IsTextureTarget(eglTarget))
29     {
30         return gl::ImageIndex();
31     }
32 
33     gl::TextureTarget target = egl_gl::EGLImageTargetToTextureTarget(eglTarget);
34     GLint mip                = static_cast<GLint>(attribs.get(EGL_GL_TEXTURE_LEVEL_KHR, 0));
35     GLint layer              = static_cast<GLint>(attribs.get(EGL_GL_TEXTURE_ZOFFSET_KHR, 0));
36 
37     if (target == gl::TextureTarget::_3D)
38     {
39         return gl::ImageIndex::Make3D(mip, layer);
40     }
41     else
42     {
43         ASSERT(layer == 0);
44         return gl::ImageIndex::MakeFromTarget(target, mip, 1);
45     }
46 }
47 
DisplayFromContext(const gl::Context * context)48 const Display *DisplayFromContext(const gl::Context *context)
49 {
50     return (context ? context->getDisplay() : nullptr);
51 }
52 
53 angle::SubjectIndex kExternalImageImplSubjectIndex = 0;
54 }  // anonymous namespace
55 
ImageSibling()56 ImageSibling::ImageSibling() : FramebufferAttachmentObject(), mSourcesOf(), mTargetOf() {}
57 
~ImageSibling()58 ImageSibling::~ImageSibling()
59 {
60     // EGL images should hold a ref to their targets and siblings, a Texture should not be deletable
61     // while it is attached to an EGL image.
62     // Child class should orphan images before destruction.
63     ASSERT(mSourcesOf.empty());
64     ASSERT(mTargetOf.get() == nullptr);
65 }
66 
setTargetImage(const gl::Context * context,egl::Image * imageTarget)67 void ImageSibling::setTargetImage(const gl::Context *context, egl::Image *imageTarget)
68 {
69     ASSERT(imageTarget != nullptr);
70     mTargetOf.set(DisplayFromContext(context), imageTarget);
71     imageTarget->addTargetSibling(this);
72 }
73 
orphanImages(const gl::Context * context)74 angle::Result ImageSibling::orphanImages(const gl::Context *context)
75 {
76     if (mTargetOf.get() != nullptr)
77     {
78         // Can't be a target and have sources.
79         ASSERT(mSourcesOf.empty());
80 
81         ANGLE_TRY(mTargetOf->orphanSibling(context, this));
82         mTargetOf.set(DisplayFromContext(context), nullptr);
83     }
84     else
85     {
86         for (Image *sourceImage : mSourcesOf)
87         {
88             ANGLE_TRY(sourceImage->orphanSibling(context, this));
89         }
90         mSourcesOf.clear();
91     }
92 
93     return angle::Result::Continue;
94 }
95 
addImageSource(egl::Image * imageSource)96 void ImageSibling::addImageSource(egl::Image *imageSource)
97 {
98     ASSERT(imageSource != nullptr);
99     mSourcesOf.insert(imageSource);
100 }
101 
removeImageSource(egl::Image * imageSource)102 void ImageSibling::removeImageSource(egl::Image *imageSource)
103 {
104     ASSERT(mSourcesOf.find(imageSource) != mSourcesOf.end());
105     mSourcesOf.erase(imageSource);
106 }
107 
isEGLImageTarget() const108 bool ImageSibling::isEGLImageTarget() const
109 {
110     return (mTargetOf.get() != nullptr);
111 }
112 
sourceEGLImageInitState() const113 gl::InitState ImageSibling::sourceEGLImageInitState() const
114 {
115     ASSERT(isEGLImageTarget());
116     return mTargetOf->sourceInitState();
117 }
118 
setSourceEGLImageInitState(gl::InitState initState) const119 void ImageSibling::setSourceEGLImageInitState(gl::InitState initState) const
120 {
121     ASSERT(isEGLImageTarget());
122     mTargetOf->setInitState(initState);
123 }
124 
isRenderable(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex) const125 bool ImageSibling::isRenderable(const gl::Context *context,
126                                 GLenum binding,
127                                 const gl::ImageIndex &imageIndex) const
128 {
129     ASSERT(isEGLImageTarget());
130     return mTargetOf->isRenderable(context);
131 }
132 
notifySiblings(angle::SubjectMessage message)133 void ImageSibling::notifySiblings(angle::SubjectMessage message)
134 {
135     if (mTargetOf.get())
136     {
137         mTargetOf->notifySiblings(this, message);
138     }
139     for (Image *source : mSourcesOf)
140     {
141         source->notifySiblings(this, message);
142     }
143 }
144 
ExternalImageSibling(rx::EGLImplFactory * factory,const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const AttributeMap & attribs)145 ExternalImageSibling::ExternalImageSibling(rx::EGLImplFactory *factory,
146                                            const gl::Context *context,
147                                            EGLenum target,
148                                            EGLClientBuffer buffer,
149                                            const AttributeMap &attribs)
150     : mImplementation(factory->createExternalImageSibling(context, target, buffer, attribs)),
151       mImplObserverBinding(this, kExternalImageImplSubjectIndex)
152 {
153     mImplObserverBinding.bind(mImplementation.get());
154 }
155 
156 ExternalImageSibling::~ExternalImageSibling() = default;
157 
onDestroy(const egl::Display * display)158 void ExternalImageSibling::onDestroy(const egl::Display *display)
159 {
160     mImplementation->onDestroy(display);
161 }
162 
initialize(const egl::Display * display)163 Error ExternalImageSibling::initialize(const egl::Display *display)
164 {
165     return mImplementation->initialize(display);
166 }
167 
getAttachmentSize(const gl::ImageIndex & imageIndex) const168 gl::Extents ExternalImageSibling::getAttachmentSize(const gl::ImageIndex &imageIndex) const
169 {
170     return mImplementation->getSize();
171 }
172 
getAttachmentFormat(GLenum binding,const gl::ImageIndex & imageIndex) const173 gl::Format ExternalImageSibling::getAttachmentFormat(GLenum binding,
174                                                      const gl::ImageIndex &imageIndex) const
175 {
176     return mImplementation->getFormat();
177 }
178 
getAttachmentSamples(const gl::ImageIndex & imageIndex) const179 GLsizei ExternalImageSibling::getAttachmentSamples(const gl::ImageIndex &imageIndex) const
180 {
181     return static_cast<GLsizei>(mImplementation->getSamples());
182 }
183 
isRenderable(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex) const184 bool ExternalImageSibling::isRenderable(const gl::Context *context,
185                                         GLenum binding,
186                                         const gl::ImageIndex &imageIndex) const
187 {
188     return mImplementation->isRenderable(context);
189 }
190 
isTextureable(const gl::Context * context) const191 bool ExternalImageSibling::isTextureable(const gl::Context *context) const
192 {
193     return mImplementation->isTexturable(context);
194 }
195 
onAttach(const gl::Context * context)196 void ExternalImageSibling::onAttach(const gl::Context *context) {}
197 
onDetach(const gl::Context * context)198 void ExternalImageSibling::onDetach(const gl::Context *context) {}
199 
getId() const200 GLuint ExternalImageSibling::getId() const
201 {
202     UNREACHABLE();
203     return 0;
204 }
205 
initState(const gl::ImageIndex & imageIndex) const206 gl::InitState ExternalImageSibling::initState(const gl::ImageIndex &imageIndex) const
207 {
208     return gl::InitState::Initialized;
209 }
210 
setInitState(const gl::ImageIndex & imageIndex,gl::InitState initState)211 void ExternalImageSibling::setInitState(const gl::ImageIndex &imageIndex, gl::InitState initState)
212 {}
213 
getImplementation() const214 rx::ExternalImageSiblingImpl *ExternalImageSibling::getImplementation() const
215 {
216     return mImplementation.get();
217 }
218 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)219 void ExternalImageSibling::onSubjectStateChange(angle::SubjectIndex index,
220                                                 angle::SubjectMessage message)
221 {
222     onStateChange(message);
223 }
224 
getAttachmentImpl() const225 rx::FramebufferAttachmentObjectImpl *ExternalImageSibling::getAttachmentImpl() const
226 {
227     return mImplementation.get();
228 }
229 
ImageState(EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)230 ImageState::ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs)
231     : label(nullptr),
232       target(target),
233       imageIndex(GetImageIndex(target, attribs)),
234       source(buffer),
235       targets(),
236       format(GL_NONE),
237       size(),
238       samples(),
239       sourceType(target),
240       colorspace(
241           static_cast<EGLenum>(attribs.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_DEFAULT_EXT)))
242 {}
243 
~ImageState()244 ImageState::~ImageState() {}
245 
Image(rx::EGLImplFactory * factory,const gl::Context * context,EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)246 Image::Image(rx::EGLImplFactory *factory,
247              const gl::Context *context,
248              EGLenum target,
249              ImageSibling *buffer,
250              const AttributeMap &attribs)
251     : mState(target, buffer, attribs),
252       mImplementation(factory->createImage(mState, context, target, attribs)),
253       mOrphanedAndNeedsInit(false)
254 {
255     ASSERT(mImplementation != nullptr);
256     ASSERT(buffer != nullptr);
257 
258     mState.source->addImageSource(this);
259 }
260 
onDestroy(const Display * display)261 void Image::onDestroy(const Display *display)
262 {
263     // All targets should hold a ref to the egl image and it should not be deleted until there are
264     // no siblings left.
265     ASSERT(mState.targets.empty());
266 
267     // Make sure the implementation gets a chance to clean up before we delete the source.
268     mImplementation->onDestroy(display);
269 
270     // Tell the source that it is no longer used by this image
271     if (mState.source != nullptr)
272     {
273         mState.source->removeImageSource(this);
274 
275         // If the source is an external object, delete it
276         if (IsExternalImageTarget(mState.sourceType))
277         {
278             ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
279             externalSibling->onDestroy(display);
280             delete externalSibling;
281         }
282 
283         mState.source = nullptr;
284     }
285 }
286 
~Image()287 Image::~Image()
288 {
289     SafeDelete(mImplementation);
290 }
291 
setLabel(EGLLabelKHR label)292 void Image::setLabel(EGLLabelKHR label)
293 {
294     mState.label = label;
295 }
296 
getLabel() const297 EGLLabelKHR Image::getLabel() const
298 {
299     return mState.label;
300 }
301 
addTargetSibling(ImageSibling * sibling)302 void Image::addTargetSibling(ImageSibling *sibling)
303 {
304     mState.targets.insert(sibling);
305 }
306 
orphanSibling(const gl::Context * context,ImageSibling * sibling)307 angle::Result Image::orphanSibling(const gl::Context *context, ImageSibling *sibling)
308 {
309     ASSERT(sibling != nullptr);
310 
311     // notify impl
312     ANGLE_TRY(mImplementation->orphan(context, sibling));
313 
314     if (mState.source == sibling)
315     {
316         // The external source of an image cannot be redefined so it cannot be orpahend.
317         ASSERT(!IsExternalImageTarget(mState.sourceType));
318 
319         // If the sibling is the source, it cannot be a target.
320         ASSERT(mState.targets.find(sibling) == mState.targets.end());
321         mState.source = nullptr;
322         mOrphanedAndNeedsInit =
323             (sibling->initState(mState.imageIndex) == gl::InitState::MayNeedInit);
324     }
325     else
326     {
327         mState.targets.erase(sibling);
328     }
329 
330     return angle::Result::Continue;
331 }
332 
getFormat() const333 const gl::Format &Image::getFormat() const
334 {
335     return mState.format;
336 }
337 
isRenderable(const gl::Context * context) const338 bool Image::isRenderable(const gl::Context *context) const
339 {
340     if (IsTextureTarget(mState.sourceType))
341     {
342         return mState.format.info->textureAttachmentSupport(context->getClientVersion(),
343                                                             context->getExtensions());
344     }
345     else if (IsRenderbufferTarget(mState.sourceType))
346     {
347         return mState.format.info->renderbufferSupport(context->getClientVersion(),
348                                                        context->getExtensions());
349     }
350     else if (IsExternalImageTarget(mState.sourceType))
351     {
352         ASSERT(mState.source != nullptr);
353         return mState.source->isRenderable(context, GL_NONE, gl::ImageIndex());
354     }
355 
356     UNREACHABLE();
357     return false;
358 }
359 
isTexturable(const gl::Context * context) const360 bool Image::isTexturable(const gl::Context *context) const
361 {
362     if (IsTextureTarget(mState.sourceType))
363     {
364         return mState.format.info->textureSupport(context->getClientVersion(),
365                                                   context->getExtensions());
366     }
367     else if (IsRenderbufferTarget(mState.sourceType))
368     {
369         return true;
370     }
371     else if (IsExternalImageTarget(mState.sourceType))
372     {
373         ASSERT(mState.source != nullptr);
374         return rx::GetAs<ExternalImageSibling>(mState.source)->isTextureable(context);
375     }
376 
377     UNREACHABLE();
378     return false;
379 }
380 
getWidth() const381 size_t Image::getWidth() const
382 {
383     return mState.size.width;
384 }
385 
getHeight() const386 size_t Image::getHeight() const
387 {
388     return mState.size.height;
389 }
390 
isLayered() const391 bool Image::isLayered() const
392 {
393     return mState.imageIndex.isLayered();
394 }
395 
getSamples() const396 size_t Image::getSamples() const
397 {
398     return mState.samples;
399 }
400 
getImplementation() const401 rx::ImageImpl *Image::getImplementation() const
402 {
403     return mImplementation;
404 }
405 
initialize(const Display * display)406 Error Image::initialize(const Display *display)
407 {
408     if (IsExternalImageTarget(mState.sourceType))
409     {
410         ANGLE_TRY(rx::GetAs<ExternalImageSibling>(mState.source)->initialize(display));
411     }
412 
413     mState.format = mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex);
414 
415     if (mState.colorspace != EGL_GL_COLORSPACE_DEFAULT_EXT)
416     {
417         GLenum nonLinearFormat = mState.format.info->sizedInternalFormat;
418         if (!gl::ColorspaceFormatOverride(mState.colorspace, &nonLinearFormat))
419         {
420             // the colorspace format is not supported
421             return egl::EglBadMatch();
422         }
423         mState.format = gl::Format(nonLinearFormat);
424     }
425 
426     mState.size    = mState.source->getAttachmentSize(mState.imageIndex);
427     mState.samples = mState.source->getAttachmentSamples(mState.imageIndex);
428 
429     return mImplementation->initialize(display);
430 }
431 
orphaned() const432 bool Image::orphaned() const
433 {
434     return (mState.source == nullptr);
435 }
436 
sourceInitState() const437 gl::InitState Image::sourceInitState() const
438 {
439     if (orphaned())
440     {
441         return mOrphanedAndNeedsInit ? gl::InitState::MayNeedInit : gl::InitState::Initialized;
442     }
443 
444     return mState.source->initState(mState.imageIndex);
445 }
446 
setInitState(gl::InitState initState)447 void Image::setInitState(gl::InitState initState)
448 {
449     if (orphaned())
450     {
451         mOrphanedAndNeedsInit = false;
452     }
453 
454     return mState.source->setInitState(mState.imageIndex, initState);
455 }
456 
notifySiblings(const ImageSibling * notifier,angle::SubjectMessage message)457 void Image::notifySiblings(const ImageSibling *notifier, angle::SubjectMessage message)
458 {
459     if (mState.source && mState.source != notifier)
460     {
461         mState.source->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
462     }
463 
464     for (ImageSibling *target : mState.targets)
465     {
466         if (target != notifier)
467         {
468             target->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
469         }
470     }
471 }
472 
473 }  // namespace egl
474