• 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,RefCountObjectReleaser<Image> * outReleaseImage)74 angle::Result ImageSibling::orphanImages(const gl::Context *context,
75                                          RefCountObjectReleaser<Image> *outReleaseImage)
76 {
77     ASSERT(outReleaseImage != nullptr);
78 
79     if (mTargetOf.get() != nullptr)
80     {
81         // Can't be a target and have sources.
82         ASSERT(mSourcesOf.empty());
83 
84         ANGLE_TRY(mTargetOf->orphanSibling(context, this));
85         *outReleaseImage = mTargetOf.set(DisplayFromContext(context), nullptr);
86     }
87     else
88     {
89         for (Image *sourceImage : mSourcesOf)
90         {
91             ANGLE_TRY(sourceImage->orphanSibling(context, this));
92         }
93         mSourcesOf.clear();
94     }
95 
96     return angle::Result::Continue;
97 }
98 
addImageSource(egl::Image * imageSource)99 void ImageSibling::addImageSource(egl::Image *imageSource)
100 {
101     ASSERT(imageSource != nullptr);
102     mSourcesOf.insert(imageSource);
103 }
104 
removeImageSource(egl::Image * imageSource)105 void ImageSibling::removeImageSource(egl::Image *imageSource)
106 {
107     ASSERT(mSourcesOf.find(imageSource) != mSourcesOf.end());
108     mSourcesOf.erase(imageSource);
109 }
110 
isEGLImageTarget() const111 bool ImageSibling::isEGLImageTarget() const
112 {
113     return (mTargetOf.get() != nullptr);
114 }
115 
sourceEGLImageInitState() const116 gl::InitState ImageSibling::sourceEGLImageInitState() const
117 {
118     ASSERT(isEGLImageTarget());
119     return mTargetOf->sourceInitState();
120 }
121 
setSourceEGLImageInitState(gl::InitState initState) const122 void ImageSibling::setSourceEGLImageInitState(gl::InitState initState) const
123 {
124     ASSERT(isEGLImageTarget());
125     mTargetOf->setInitState(initState);
126 }
127 
isRenderable(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex) const128 bool ImageSibling::isRenderable(const gl::Context *context,
129                                 GLenum binding,
130                                 const gl::ImageIndex &imageIndex) const
131 {
132     ASSERT(isEGLImageTarget());
133     return mTargetOf->isRenderable(context);
134 }
135 
isYUV() const136 bool ImageSibling::isYUV() const
137 {
138     return mTargetOf.get() && mTargetOf->isYUV();
139 }
140 
hasProtectedContent() const141 bool ImageSibling::hasProtectedContent() const
142 {
143     return mTargetOf.get() && mTargetOf->hasProtectedContent();
144 }
145 
notifySiblings(angle::SubjectMessage message)146 void ImageSibling::notifySiblings(angle::SubjectMessage message)
147 {
148     if (mTargetOf.get())
149     {
150         mTargetOf->notifySiblings(this, message);
151     }
152     for (Image *source : mSourcesOf)
153     {
154         source->notifySiblings(this, message);
155     }
156 }
157 
ExternalImageSibling(rx::EGLImplFactory * factory,const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const AttributeMap & attribs)158 ExternalImageSibling::ExternalImageSibling(rx::EGLImplFactory *factory,
159                                            const gl::Context *context,
160                                            EGLenum target,
161                                            EGLClientBuffer buffer,
162                                            const AttributeMap &attribs)
163     : mImplementation(factory->createExternalImageSibling(context, target, buffer, attribs)),
164       mImplObserverBinding(this, kExternalImageImplSubjectIndex)
165 {
166     mImplObserverBinding.bind(mImplementation.get());
167 }
168 
169 ExternalImageSibling::~ExternalImageSibling() = default;
170 
onDestroy(const egl::Display * display)171 void ExternalImageSibling::onDestroy(const egl::Display *display)
172 {
173     mImplementation->onDestroy(display);
174 }
175 
initialize(const egl::Display * display)176 Error ExternalImageSibling::initialize(const egl::Display *display)
177 {
178     return mImplementation->initialize(display);
179 }
180 
getAttachmentSize(const gl::ImageIndex & imageIndex) const181 gl::Extents ExternalImageSibling::getAttachmentSize(const gl::ImageIndex &imageIndex) const
182 {
183     return mImplementation->getSize();
184 }
185 
getAttachmentFormat(GLenum binding,const gl::ImageIndex & imageIndex) const186 gl::Format ExternalImageSibling::getAttachmentFormat(GLenum binding,
187                                                      const gl::ImageIndex &imageIndex) const
188 {
189     return mImplementation->getFormat();
190 }
191 
getAttachmentSamples(const gl::ImageIndex & imageIndex) const192 GLsizei ExternalImageSibling::getAttachmentSamples(const gl::ImageIndex &imageIndex) const
193 {
194     return static_cast<GLsizei>(mImplementation->getSamples());
195 }
196 
getLevelCount() const197 GLuint ExternalImageSibling::getLevelCount() const
198 {
199     return static_cast<GLuint>(mImplementation->getLevelCount());
200 }
201 
isRenderable(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex) const202 bool ExternalImageSibling::isRenderable(const gl::Context *context,
203                                         GLenum binding,
204                                         const gl::ImageIndex &imageIndex) const
205 {
206     return mImplementation->isRenderable(context);
207 }
208 
isTextureable(const gl::Context * context) const209 bool ExternalImageSibling::isTextureable(const gl::Context *context) const
210 {
211     return mImplementation->isTexturable(context);
212 }
213 
isYUV() const214 bool ExternalImageSibling::isYUV() const
215 {
216     return mImplementation->isYUV();
217 }
218 
isCubeMap() const219 bool ExternalImageSibling::isCubeMap() const
220 {
221     return mImplementation->isCubeMap();
222 }
223 
hasProtectedContent() const224 bool ExternalImageSibling::hasProtectedContent() const
225 {
226     return mImplementation->hasProtectedContent();
227 }
228 
onAttach(const gl::Context * context,rx::Serial framebufferSerial)229 void ExternalImageSibling::onAttach(const gl::Context *context, rx::Serial framebufferSerial) {}
230 
onDetach(const gl::Context * context,rx::Serial framebufferSerial)231 void ExternalImageSibling::onDetach(const gl::Context *context, rx::Serial framebufferSerial) {}
232 
getId() const233 GLuint ExternalImageSibling::getId() const
234 {
235     UNREACHABLE();
236     return 0;
237 }
238 
initState(const gl::ImageIndex & imageIndex) const239 gl::InitState ExternalImageSibling::initState(const gl::ImageIndex &imageIndex) const
240 {
241     return gl::InitState::Initialized;
242 }
243 
setInitState(const gl::ImageIndex & imageIndex,gl::InitState initState)244 void ExternalImageSibling::setInitState(const gl::ImageIndex &imageIndex, gl::InitState initState)
245 {}
246 
getImplementation() const247 rx::ExternalImageSiblingImpl *ExternalImageSibling::getImplementation() const
248 {
249     return mImplementation.get();
250 }
251 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)252 void ExternalImageSibling::onSubjectStateChange(angle::SubjectIndex index,
253                                                 angle::SubjectMessage message)
254 {
255     onStateChange(message);
256 }
257 
getAttachmentImpl() const258 rx::FramebufferAttachmentObjectImpl *ExternalImageSibling::getAttachmentImpl() const
259 {
260     return mImplementation.get();
261 }
262 
ImageState(EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)263 ImageState::ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs)
264     : label(nullptr),
265       target(target),
266       imageIndex(GetImageIndex(target, attribs)),
267       source(buffer),
268       targets(),
269       format(GL_NONE),
270       yuv(false),
271       cubeMap(false),
272       size(),
273       samples(),
274       levelCount(1),
275       sourceType(target),
276       colorspace(
277           static_cast<EGLenum>(attribs.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_DEFAULT_EXT))),
278       hasProtectedContent(static_cast<bool>(attribs.get(EGL_PROTECTED_CONTENT_EXT, EGL_FALSE)))
279 {}
280 
~ImageState()281 ImageState::~ImageState() {}
282 
Image(rx::EGLImplFactory * factory,const gl::Context * context,EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)283 Image::Image(rx::EGLImplFactory *factory,
284              const gl::Context *context,
285              EGLenum target,
286              ImageSibling *buffer,
287              const AttributeMap &attribs)
288     : mState(target, buffer, attribs),
289       mImplementation(factory->createImage(mState, context, target, attribs)),
290       mOrphanedAndNeedsInit(false)
291 {
292     ASSERT(mImplementation != nullptr);
293     ASSERT(buffer != nullptr);
294     ASSERT(context == nullptr || context->isShared());
295 
296     mState.source->addImageSource(this);
297 }
298 
onDestroy(const Display * display)299 void Image::onDestroy(const Display *display)
300 {
301     // All targets should hold a ref to the egl image and it should not be deleted until there are
302     // no siblings left.
303     ASSERT(mState.targets.empty());
304 
305     // Make sure the implementation gets a chance to clean up before we delete the source.
306     mImplementation->onDestroy(display);
307 
308     // Tell the source that it is no longer used by this image
309     if (mState.source != nullptr)
310     {
311         mState.source->removeImageSource(this);
312 
313         // If the source is an external object, delete it
314         if (IsExternalImageTarget(mState.sourceType))
315         {
316             ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
317             externalSibling->onDestroy(display);
318             delete externalSibling;
319         }
320 
321         mState.source = nullptr;
322     }
323 }
324 
~Image()325 Image::~Image()
326 {
327     SafeDelete(mImplementation);
328 }
329 
setLabel(EGLLabelKHR label)330 void Image::setLabel(EGLLabelKHR label)
331 {
332     mState.label = label;
333 }
334 
getLabel() const335 EGLLabelKHR Image::getLabel() const
336 {
337     return mState.label;
338 }
339 
addTargetSibling(ImageSibling * sibling)340 void Image::addTargetSibling(ImageSibling *sibling)
341 {
342     mState.targets.insert(sibling);
343 }
344 
orphanSibling(const gl::Context * context,ImageSibling * sibling)345 angle::Result Image::orphanSibling(const gl::Context *context, ImageSibling *sibling)
346 {
347     ASSERT(sibling != nullptr);
348 
349     // notify impl
350     ANGLE_TRY(mImplementation->orphan(context, sibling));
351 
352     if (mState.source == sibling)
353     {
354         // The external source of an image cannot be redefined so it cannot be orpahend.
355         ASSERT(!IsExternalImageTarget(mState.sourceType));
356 
357         // If the sibling is the source, it cannot be a target.
358         ASSERT(mState.targets.find(sibling) == mState.targets.end());
359         mState.source = nullptr;
360         mOrphanedAndNeedsInit =
361             (sibling->initState(mState.imageIndex) == gl::InitState::MayNeedInit);
362     }
363     else
364     {
365         mState.targets.erase(sibling);
366     }
367 
368     return angle::Result::Continue;
369 }
370 
getFormat() const371 const gl::Format &Image::getFormat() const
372 {
373     return mState.format;
374 }
375 
isRenderable(const gl::Context * context) const376 bool Image::isRenderable(const gl::Context *context) const
377 {
378     if (IsTextureTarget(mState.sourceType))
379     {
380         return mState.format.info->textureAttachmentSupport(context->getClientVersion(),
381                                                             context->getExtensions());
382     }
383     else if (IsRenderbufferTarget(mState.sourceType))
384     {
385         return mState.format.info->renderbufferSupport(context->getClientVersion(),
386                                                        context->getExtensions());
387     }
388     else if (IsExternalImageTarget(mState.sourceType))
389     {
390         ASSERT(mState.source != nullptr);
391         return mState.source->isRenderable(context, GL_NONE, gl::ImageIndex());
392     }
393 
394     UNREACHABLE();
395     return false;
396 }
397 
isTexturable(const gl::Context * context) const398 bool Image::isTexturable(const gl::Context *context) const
399 {
400     if (IsTextureTarget(mState.sourceType))
401     {
402         return mState.format.info->textureSupport(context->getClientVersion(),
403                                                   context->getExtensions());
404     }
405     else if (IsRenderbufferTarget(mState.sourceType))
406     {
407         return true;
408     }
409     else if (IsExternalImageTarget(mState.sourceType))
410     {
411         ASSERT(mState.source != nullptr);
412         return rx::GetAs<ExternalImageSibling>(mState.source)->isTextureable(context);
413     }
414 
415     UNREACHABLE();
416     return false;
417 }
418 
isYUV() const419 bool Image::isYUV() const
420 {
421     return mState.yuv;
422 }
423 
isCubeMap() const424 bool Image::isCubeMap() const
425 {
426     return mState.cubeMap;
427 }
428 
getWidth() const429 size_t Image::getWidth() const
430 {
431     return mState.size.width;
432 }
433 
getHeight() const434 size_t Image::getHeight() const
435 {
436     return mState.size.height;
437 }
438 
getExtents() const439 const gl::Extents &Image::getExtents() const
440 {
441     return mState.size;
442 }
443 
isLayered() const444 bool Image::isLayered() const
445 {
446     return mState.imageIndex.isLayered();
447 }
448 
getSamples() const449 size_t Image::getSamples() const
450 {
451     return mState.samples;
452 }
453 
getLevelCount() const454 GLuint Image::getLevelCount() const
455 {
456     return mState.levelCount;
457 }
458 
hasProtectedContent() const459 bool Image::hasProtectedContent() const
460 {
461     return mState.hasProtectedContent;
462 }
463 
getImplementation() const464 rx::ImageImpl *Image::getImplementation() const
465 {
466     return mImplementation;
467 }
468 
initialize(const Display * display)469 Error Image::initialize(const Display *display)
470 {
471     if (IsExternalImageTarget(mState.sourceType))
472     {
473         ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
474         ANGLE_TRY(externalSibling->initialize(display));
475 
476         mState.hasProtectedContent = externalSibling->hasProtectedContent();
477         mState.levelCount          = externalSibling->getLevelCount();
478         mState.cubeMap             = externalSibling->isCubeMap();
479         // Only external siblings can be YUV
480         mState.yuv = externalSibling->isYUV();
481     }
482 
483     mState.format = mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex);
484 
485     if (mState.colorspace != EGL_GL_COLORSPACE_DEFAULT_EXT)
486     {
487         GLenum nonLinearFormat = mState.format.info->sizedInternalFormat;
488         if (!gl::ColorspaceFormatOverride(mState.colorspace, &nonLinearFormat))
489         {
490             // the colorspace format is not supported
491             return egl::EglBadMatch();
492         }
493         mState.format = gl::Format(nonLinearFormat);
494     }
495 
496     mState.size    = mState.source->getAttachmentSize(mState.imageIndex);
497     mState.samples = mState.source->getAttachmentSamples(mState.imageIndex);
498 
499     if (IsTextureTarget(mState.sourceType))
500     {
501         mState.size.depth = 1;
502     }
503 
504     return mImplementation->initialize(display);
505 }
506 
orphaned() const507 bool Image::orphaned() const
508 {
509     return (mState.source == nullptr);
510 }
511 
sourceInitState() const512 gl::InitState Image::sourceInitState() const
513 {
514     if (orphaned())
515     {
516         return mOrphanedAndNeedsInit ? gl::InitState::MayNeedInit : gl::InitState::Initialized;
517     }
518 
519     return mState.source->initState(mState.imageIndex);
520 }
521 
setInitState(gl::InitState initState)522 void Image::setInitState(gl::InitState initState)
523 {
524     if (orphaned())
525     {
526         mOrphanedAndNeedsInit = false;
527     }
528 
529     return mState.source->setInitState(mState.imageIndex, initState);
530 }
531 
exportVkImage(void * vkImage,void * vkImageCreateInfo)532 Error Image::exportVkImage(void *vkImage, void *vkImageCreateInfo)
533 {
534     return mImplementation->exportVkImage(vkImage, vkImageCreateInfo);
535 }
536 
notifySiblings(const ImageSibling * notifier,angle::SubjectMessage message)537 void Image::notifySiblings(const ImageSibling *notifier, angle::SubjectMessage message)
538 {
539     if (mState.source && mState.source != notifier)
540     {
541         mState.source->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
542     }
543 
544     for (ImageSibling *target : mState.targets)
545     {
546         if (target != notifier)
547         {
548             target->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
549         }
550     }
551 }
552 
553 }  // namespace egl
554