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/Display.h"
15 #include "libANGLE/Renderbuffer.h"
16 #include "libANGLE/Texture.h"
17 #include "libANGLE/angletypes.h"
18 #include "libANGLE/formatutils.h"
19 #include "libANGLE/renderer/EGLImplFactory.h"
20 #include "libANGLE/renderer/ImageImpl.h"
21 
22 namespace egl
23 {
24 
25 namespace
26 {
GetImageIndex(EGLenum eglTarget,const egl::AttributeMap & attribs)27 gl::ImageIndex GetImageIndex(EGLenum eglTarget, const egl::AttributeMap &attribs)
28 {
29     if (!IsTextureTarget(eglTarget))
30     {
31         return gl::ImageIndex();
32     }
33 
34     gl::TextureTarget target = egl_gl::EGLImageTargetToTextureTarget(eglTarget);
35     GLint mip                = static_cast<GLint>(attribs.get(EGL_GL_TEXTURE_LEVEL_KHR, 0));
36     GLint layer              = static_cast<GLint>(attribs.get(EGL_GL_TEXTURE_ZOFFSET_KHR, 0));
37 
38     if (target == gl::TextureTarget::_3D)
39     {
40         return gl::ImageIndex::Make3D(mip, layer);
41     }
42     else
43     {
44         ASSERT(layer == 0);
45         return gl::ImageIndex::MakeFromTarget(target, mip, 1);
46     }
47 }
48 
DisplayFromContext(const gl::Context * context)49 const Display *DisplayFromContext(const gl::Context *context)
50 {
51     return (context ? context->getDisplay() : nullptr);
52 }
53 
54 angle::SubjectIndex kExternalImageImplSubjectIndex = 0;
55 }  // anonymous namespace
56 
ImageSibling()57 ImageSibling::ImageSibling() : FramebufferAttachmentObject(), mSourcesOf(), mTargetOf() {}
58 
~ImageSibling()59 ImageSibling::~ImageSibling()
60 {
61     // EGL images should hold a ref to their targets and siblings, a Texture should not be deletable
62     // while it is attached to an EGL image.
63     // Child class should orphan images before destruction.
64     ASSERT(mSourcesOf.empty());
65     ASSERT(mTargetOf.get() == nullptr);
66 }
67 
setTargetImage(const gl::Context * context,egl::Image * imageTarget)68 void ImageSibling::setTargetImage(const gl::Context *context, egl::Image *imageTarget)
69 {
70     ASSERT(imageTarget != nullptr);
71     mTargetOf.set(DisplayFromContext(context), imageTarget);
72     imageTarget->addTargetSibling(this);
73 }
74 
orphanImages(const gl::Context * context,RefCountObjectReleaser<Image> * outReleaseImage)75 angle::Result ImageSibling::orphanImages(const gl::Context *context,
76                                          RefCountObjectReleaser<Image> *outReleaseImage)
77 {
78     ASSERT(outReleaseImage != nullptr);
79 
80     if (mTargetOf.get() != nullptr)
81     {
82         // Can't be a target and have sources.
83         ASSERT(mSourcesOf.empty());
84 
85         ANGLE_TRY(mTargetOf->orphanSibling(context, this));
86         *outReleaseImage = mTargetOf.set(DisplayFromContext(context), nullptr);
87     }
88     else
89     {
90         for (Image *sourceImage : mSourcesOf)
91         {
92             ANGLE_TRY(sourceImage->orphanSibling(context, this));
93         }
94         mSourcesOf.clear();
95     }
96 
97     return angle::Result::Continue;
98 }
99 
addImageSource(egl::Image * imageSource)100 void ImageSibling::addImageSource(egl::Image *imageSource)
101 {
102     ASSERT(imageSource != nullptr);
103     mSourcesOf.insert(imageSource);
104 }
105 
removeImageSource(egl::Image * imageSource)106 void ImageSibling::removeImageSource(egl::Image *imageSource)
107 {
108     ASSERT(mSourcesOf.find(imageSource) != mSourcesOf.end());
109     mSourcesOf.erase(imageSource);
110 }
111 
isEGLImageTarget() const112 bool ImageSibling::isEGLImageTarget() const
113 {
114     return (mTargetOf.get() != nullptr);
115 }
116 
sourceEGLImageInitState() const117 gl::InitState ImageSibling::sourceEGLImageInitState() const
118 {
119     ASSERT(isEGLImageTarget());
120     return mTargetOf->sourceInitState();
121 }
122 
setSourceEGLImageInitState(gl::InitState initState) const123 void ImageSibling::setSourceEGLImageInitState(gl::InitState initState) const
124 {
125     ASSERT(isEGLImageTarget());
126     mTargetOf->setInitState(initState);
127 }
128 
isRenderable(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex) const129 bool ImageSibling::isRenderable(const gl::Context *context,
130                                 GLenum binding,
131                                 const gl::ImageIndex &imageIndex) const
132 {
133     ASSERT(isEGLImageTarget());
134     return mTargetOf->isRenderable(context);
135 }
136 
isYUV() const137 bool ImageSibling::isYUV() const
138 {
139     return mTargetOf.get() && mTargetOf->isYUV();
140 }
141 
isExternalImageWithoutIndividualSync() const142 bool ImageSibling::isExternalImageWithoutIndividualSync() const
143 {
144     return mTargetOf.get() && mTargetOf->isExternalImageWithoutIndividualSync();
145 }
146 
hasFrontBufferUsage() const147 bool ImageSibling::hasFrontBufferUsage() const
148 {
149     return mTargetOf.get() && mTargetOf->hasFrontBufferUsage();
150 }
151 
hasProtectedContent() const152 bool ImageSibling::hasProtectedContent() const
153 {
154     return mTargetOf.get() && mTargetOf->hasProtectedContent();
155 }
156 
notifySiblings(angle::SubjectMessage message)157 void ImageSibling::notifySiblings(angle::SubjectMessage message)
158 {
159     if (mTargetOf.get())
160     {
161         mTargetOf->notifySiblings(this, message);
162     }
163     for (Image *source : mSourcesOf)
164     {
165         source->notifySiblings(this, message);
166     }
167 }
168 
ExternalImageSibling(rx::EGLImplFactory * factory,const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const AttributeMap & attribs)169 ExternalImageSibling::ExternalImageSibling(rx::EGLImplFactory *factory,
170                                            const gl::Context *context,
171                                            EGLenum target,
172                                            EGLClientBuffer buffer,
173                                            const AttributeMap &attribs)
174     : mImplementation(factory->createExternalImageSibling(context, target, buffer, attribs)),
175       mImplObserverBinding(this, kExternalImageImplSubjectIndex)
176 {
177     mImplObserverBinding.bind(mImplementation.get());
178 }
179 
180 ExternalImageSibling::~ExternalImageSibling() = default;
181 
onDestroy(const egl::Display * display)182 void ExternalImageSibling::onDestroy(const egl::Display *display)
183 {
184     mImplementation->onDestroy(display);
185 }
186 
initialize(const egl::Display * display,const gl::Context * context)187 Error ExternalImageSibling::initialize(const egl::Display *display, const gl::Context *context)
188 {
189     return mImplementation->initialize(display);
190 }
191 
getAttachmentSize(const gl::ImageIndex & imageIndex) const192 gl::Extents ExternalImageSibling::getAttachmentSize(const gl::ImageIndex &imageIndex) const
193 {
194     return mImplementation->getSize();
195 }
196 
getAttachmentFormat(GLenum binding,const gl::ImageIndex & imageIndex) const197 gl::Format ExternalImageSibling::getAttachmentFormat(GLenum binding,
198                                                      const gl::ImageIndex &imageIndex) const
199 {
200     return mImplementation->getFormat();
201 }
202 
getAttachmentSamples(const gl::ImageIndex & imageIndex) const203 GLsizei ExternalImageSibling::getAttachmentSamples(const gl::ImageIndex &imageIndex) const
204 {
205     return static_cast<GLsizei>(mImplementation->getSamples());
206 }
207 
getLevelCount() const208 GLuint ExternalImageSibling::getLevelCount() const
209 {
210     return static_cast<GLuint>(mImplementation->getLevelCount());
211 }
212 
isRenderable(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex) const213 bool ExternalImageSibling::isRenderable(const gl::Context *context,
214                                         GLenum binding,
215                                         const gl::ImageIndex &imageIndex) const
216 {
217     return mImplementation->isRenderable(context);
218 }
219 
isTextureable(const gl::Context * context) const220 bool ExternalImageSibling::isTextureable(const gl::Context *context) const
221 {
222     return mImplementation->isTexturable(context);
223 }
224 
isYUV() const225 bool ExternalImageSibling::isYUV() const
226 {
227     return mImplementation->isYUV();
228 }
229 
hasFrontBufferUsage() const230 bool ExternalImageSibling::hasFrontBufferUsage() const
231 {
232     return mImplementation->hasFrontBufferUsage();
233 }
234 
isCubeMap() const235 bool ExternalImageSibling::isCubeMap() const
236 {
237     return mImplementation->isCubeMap();
238 }
239 
hasProtectedContent() const240 bool ExternalImageSibling::hasProtectedContent() const
241 {
242     return mImplementation->hasProtectedContent();
243 }
244 
onAttach(const gl::Context * context,rx::UniqueSerial framebufferSerial)245 void ExternalImageSibling::onAttach(const gl::Context *context, rx::UniqueSerial framebufferSerial)
246 {}
247 
onDetach(const gl::Context * context,rx::UniqueSerial framebufferSerial)248 void ExternalImageSibling::onDetach(const gl::Context *context, rx::UniqueSerial framebufferSerial)
249 {}
250 
getId() const251 GLuint ExternalImageSibling::getId() const
252 {
253     UNREACHABLE();
254     return 0;
255 }
256 
initState(GLenum binding,const gl::ImageIndex & imageIndex) const257 gl::InitState ExternalImageSibling::initState(GLenum binding,
258                                               const gl::ImageIndex &imageIndex) const
259 {
260     return gl::InitState::Initialized;
261 }
262 
setInitState(GLenum binding,const gl::ImageIndex & imageIndex,gl::InitState initState)263 void ExternalImageSibling::setInitState(GLenum binding,
264                                         const gl::ImageIndex &imageIndex,
265                                         gl::InitState initState)
266 {}
267 
getImplementation() const268 rx::ExternalImageSiblingImpl *ExternalImageSibling::getImplementation() const
269 {
270     return mImplementation.get();
271 }
272 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)273 void ExternalImageSibling::onSubjectStateChange(angle::SubjectIndex index,
274                                                 angle::SubjectMessage message)
275 {
276     onStateChange(message);
277 }
278 
getAttachmentImpl() const279 rx::FramebufferAttachmentObjectImpl *ExternalImageSibling::getAttachmentImpl() const
280 {
281     return mImplementation.get();
282 }
283 
ImageState(ImageID id,EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)284 ImageState::ImageState(ImageID id,
285                        EGLenum target,
286                        ImageSibling *buffer,
287                        const AttributeMap &attribs)
288     : id(id),
289       label(nullptr),
290       target(target),
291       imageIndex(GetImageIndex(target, attribs)),
292       source(buffer),
293       format(GL_NONE),
294       yuv(false),
295       cubeMap(false),
296       size(),
297       samples(),
298       levelCount(1),
299       colorspace(
300           static_cast<EGLenum>(attribs.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_DEFAULT_EXT))),
301       hasProtectedContent(static_cast<bool>(attribs.get(EGL_PROTECTED_CONTENT_EXT, EGL_FALSE)))
302 {}
303 
~ImageState()304 ImageState::~ImageState() {}
305 
Image(rx::EGLImplFactory * factory,ImageID id,const gl::Context * context,EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)306 Image::Image(rx::EGLImplFactory *factory,
307              ImageID id,
308              const gl::Context *context,
309              EGLenum target,
310              ImageSibling *buffer,
311              const AttributeMap &attribs)
312     : mState(id, target, buffer, attribs),
313       mImplementation(factory->createImage(mState, context, target, attribs)),
314       mOrphanedAndNeedsInit(false),
315       mSharedContextMutex(nullptr)
316 {
317     ASSERT(mImplementation != nullptr);
318     ASSERT(buffer != nullptr);
319 
320     if (kIsSharedContextMutexEnabled && context != nullptr)
321     {
322         ASSERT(context->isSharedContextMutexActive());
323         mSharedContextMutex = context->getContextMutex();
324         mSharedContextMutex->addRef();
325     }
326 
327     mState.source->addImageSource(this);
328 }
329 
onDestroy(const Display * display)330 void Image::onDestroy(const Display *display)
331 {
332     // All targets should hold a ref to the egl image and it should not be deleted until there are
333     // no siblings left.
334     ASSERT([&] {
335         std::unique_lock lock(mState.targetsLock);
336         return mState.targets.empty();
337     }());
338 
339     // Make sure the implementation gets a chance to clean up before we delete the source.
340     mImplementation->onDestroy(display);
341 
342     // Tell the source that it is no longer used by this image
343     if (mState.source != nullptr)
344     {
345         mState.source->removeImageSource(this);
346 
347         // If the source is an external object, delete it
348         if (IsExternalImageTarget(mState.target))
349         {
350             ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
351             externalSibling->onDestroy(display);
352             delete externalSibling;
353         }
354 
355         mState.source = nullptr;
356     }
357 }
358 
~Image()359 Image::~Image()
360 {
361     SafeDelete(mImplementation);
362 
363     if (mSharedContextMutex != nullptr)
364     {
365         mSharedContextMutex->release();
366         mSharedContextMutex = nullptr;
367     }
368 }
369 
setLabel(EGLLabelKHR label)370 void Image::setLabel(EGLLabelKHR label)
371 {
372     mState.label = label;
373 }
374 
getLabel() const375 EGLLabelKHR Image::getLabel() const
376 {
377     return mState.label;
378 }
379 
addTargetSibling(ImageSibling * sibling)380 void Image::addTargetSibling(ImageSibling *sibling)
381 {
382     std::unique_lock lock(mState.targetsLock);
383     mState.targets.insert(sibling);
384 }
385 
orphanSibling(const gl::Context * context,ImageSibling * sibling)386 angle::Result Image::orphanSibling(const gl::Context *context, ImageSibling *sibling)
387 {
388     ASSERT(sibling != nullptr);
389 
390     // notify impl
391     ANGLE_TRY(mImplementation->orphan(context, sibling));
392 
393     if (mState.source == sibling)
394     {
395         // The external source of an image cannot be redefined so it cannot be orphaned.
396         ASSERT(!IsExternalImageTarget(mState.target));
397 
398         // If the sibling is the source, it cannot be a target.
399         ASSERT([&] {
400             std::unique_lock lock(mState.targetsLock);
401             return mState.targets.find(sibling) == mState.targets.end();
402         }());
403         mState.source = nullptr;
404         mOrphanedAndNeedsInit =
405             (sibling->initState(GL_NONE, mState.imageIndex) == gl::InitState::MayNeedInit);
406     }
407     else
408     {
409         std::unique_lock lock(mState.targetsLock);
410         mState.targets.erase(sibling);
411     }
412 
413     return angle::Result::Continue;
414 }
415 
getFormat() const416 const gl::Format &Image::getFormat() const
417 {
418     return mState.format;
419 }
420 
isRenderable(const gl::Context * context) const421 bool Image::isRenderable(const gl::Context *context) const
422 {
423     return mIsRenderable;
424 }
425 
isTexturable(const gl::Context * context) const426 bool Image::isTexturable(const gl::Context *context) const
427 {
428     return mIsTexturable;
429 }
430 
isYUV() const431 bool Image::isYUV() const
432 {
433     return mState.yuv;
434 }
435 
isExternalImageWithoutIndividualSync() const436 bool Image::isExternalImageWithoutIndividualSync() const
437 {
438     // Only Vulkan images are individually synced.
439     return IsExternalImageTarget(mState.target) && mState.target != EGL_VULKAN_IMAGE_ANGLE;
440 }
441 
hasFrontBufferUsage() const442 bool Image::hasFrontBufferUsage() const
443 {
444     if (IsExternalImageTarget(mState.target))
445     {
446         ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
447         return externalSibling->hasFrontBufferUsage();
448     }
449 
450     return false;
451 }
452 
isCubeMap() const453 bool Image::isCubeMap() const
454 {
455     return mState.cubeMap;
456 }
457 
getWidth() const458 size_t Image::getWidth() const
459 {
460     return mState.size.width;
461 }
462 
getHeight() const463 size_t Image::getHeight() const
464 {
465     return mState.size.height;
466 }
467 
getExtents() const468 const gl::Extents &Image::getExtents() const
469 {
470     return mState.size;
471 }
472 
isLayered() const473 bool Image::isLayered() const
474 {
475     return mState.imageIndex.isLayered();
476 }
477 
getSamples() const478 size_t Image::getSamples() const
479 {
480     return mState.samples;
481 }
482 
getLevelCount() const483 GLuint Image::getLevelCount() const
484 {
485     return mState.levelCount;
486 }
487 
hasProtectedContent() const488 bool Image::hasProtectedContent() const
489 {
490     return mState.hasProtectedContent;
491 }
492 
getImplementation() const493 rx::ImageImpl *Image::getImplementation() const
494 {
495     return mImplementation;
496 }
497 
initialize(const Display * display,const gl::Context * context)498 Error Image::initialize(const Display *display, const gl::Context *context)
499 {
500     if (kIsSharedContextMutexEnabled && mSharedContextMutex == nullptr)
501     {
502         mSharedContextMutex = display->getSharedContextMutexManager()->create();
503         mSharedContextMutex->addRef();
504     }
505 
506     if (IsExternalImageTarget(mState.target))
507     {
508         ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
509         ANGLE_TRY(externalSibling->initialize(display, context));
510 
511         mState.hasProtectedContent = externalSibling->hasProtectedContent();
512         mState.levelCount          = externalSibling->getLevelCount();
513         mState.cubeMap             = externalSibling->isCubeMap();
514 
515         // External siblings can be YUV
516         mState.yuv = externalSibling->isYUV();
517     }
518 
519     mState.format = mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex);
520 
521     if (mState.colorspace != EGL_GL_COLORSPACE_DEFAULT_EXT)
522     {
523         GLenum nonLinearFormat = mState.format.info->sizedInternalFormat;
524         if (!gl::ColorspaceFormatOverride(mState.colorspace, &nonLinearFormat))
525         {
526             // the colorspace format is not supported
527             return egl::EglBadMatch();
528         }
529         mState.format = gl::Format(nonLinearFormat);
530     }
531 
532     if (!IsExternalImageTarget(mState.target))
533     {
534         // Account for the fact that GL_ANGLE_yuv_internal_format extension maybe enabled,
535         // in which case the internal format itself could be YUV.
536         mState.yuv = gl::IsYuvFormat(mState.format.info->sizedInternalFormat);
537     }
538 
539     mState.size    = mState.source->getAttachmentSize(mState.imageIndex);
540     mState.samples = mState.source->getAttachmentSamples(mState.imageIndex);
541 
542     if (IsTextureTarget(mState.target))
543     {
544         mState.size.depth = 1;
545     }
546 
547     Error error = mImplementation->initialize(display);
548     if (error.isError())
549     {
550         return error;
551     }
552 
553     if (IsTextureTarget(mState.target))
554     {
555         mIsTexturable = true;
556         mIsRenderable = mState.format.info->textureAttachmentSupport(context->getClientVersion(),
557                                                                      context->getExtensions());
558     }
559     else if (IsRenderbufferTarget(mState.target))
560     {
561         mIsTexturable = true;
562         mIsRenderable = mState.format.info->renderbufferSupport(context->getClientVersion(),
563                                                                 context->getExtensions());
564     }
565     else if (IsExternalImageTarget(mState.target))
566     {
567         ASSERT(mState.source != nullptr);
568         mIsTexturable = rx::GetAs<ExternalImageSibling>(mState.source)->isTextureable(context);
569         mIsRenderable = rx::GetAs<ExternalImageSibling>(mState.source)
570                             ->isRenderable(context, GL_NONE, gl::ImageIndex());
571     }
572     else
573     {
574         UNREACHABLE();
575     }
576 
577     return NoError();
578 }
579 
orphaned() const580 bool Image::orphaned() const
581 {
582     return (mState.source == nullptr);
583 }
584 
sourceInitState() const585 gl::InitState Image::sourceInitState() const
586 {
587     if (orphaned())
588     {
589         return mOrphanedAndNeedsInit ? gl::InitState::MayNeedInit : gl::InitState::Initialized;
590     }
591 
592     return mState.source->initState(GL_NONE, mState.imageIndex);
593 }
594 
setInitState(gl::InitState initState)595 void Image::setInitState(gl::InitState initState)
596 {
597     if (orphaned())
598     {
599         mOrphanedAndNeedsInit = false;
600     }
601 
602     return mState.source->setInitState(GL_NONE, mState.imageIndex, initState);
603 }
604 
exportVkImage(void * vkImage,void * vkImageCreateInfo)605 Error Image::exportVkImage(void *vkImage, void *vkImageCreateInfo)
606 {
607     return mImplementation->exportVkImage(vkImage, vkImageCreateInfo);
608 }
609 
notifySiblings(const ImageSibling * notifier,angle::SubjectMessage message)610 void Image::notifySiblings(const ImageSibling *notifier, angle::SubjectMessage message)
611 {
612     if (mState.source && mState.source != notifier)
613     {
614         mState.source->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
615     }
616 
617     std::unique_lock lock(mState.targetsLock);
618     for (ImageSibling *target : mState.targets)
619     {
620         if (target != notifier)
621         {
622             target->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
623         }
624     }
625 }
626 
627 }  // namespace egl
628