xref: /aosp_15_r20/external/angle/src/libANGLE/Image.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 
isExternalImageWithoutIndividualSync() const141 bool ImageSibling::isExternalImageWithoutIndividualSync() const
142 {
143     return mTargetOf.get() && mTargetOf->isExternalImageWithoutIndividualSync();
144 }
145 
hasFrontBufferUsage() const146 bool ImageSibling::hasFrontBufferUsage() const
147 {
148     return mTargetOf.get() && mTargetOf->hasFrontBufferUsage();
149 }
150 
hasProtectedContent() const151 bool ImageSibling::hasProtectedContent() const
152 {
153     return mTargetOf.get() && mTargetOf->hasProtectedContent();
154 }
155 
notifySiblings(angle::SubjectMessage message)156 void ImageSibling::notifySiblings(angle::SubjectMessage message)
157 {
158     if (mTargetOf.get())
159     {
160         mTargetOf->notifySiblings(this, message);
161     }
162     for (Image *source : mSourcesOf)
163     {
164         source->notifySiblings(this, message);
165     }
166 }
167 
ExternalImageSibling(rx::EGLImplFactory * factory,const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const AttributeMap & attribs)168 ExternalImageSibling::ExternalImageSibling(rx::EGLImplFactory *factory,
169                                            const gl::Context *context,
170                                            EGLenum target,
171                                            EGLClientBuffer buffer,
172                                            const AttributeMap &attribs)
173     : mImplementation(factory->createExternalImageSibling(context, target, buffer, attribs)),
174       mImplObserverBinding(this, kExternalImageImplSubjectIndex)
175 {
176     mImplObserverBinding.bind(mImplementation.get());
177 }
178 
179 ExternalImageSibling::~ExternalImageSibling() = default;
180 
onDestroy(const egl::Display * display)181 void ExternalImageSibling::onDestroy(const egl::Display *display)
182 {
183     mImplementation->onDestroy(display);
184 }
185 
initialize(const egl::Display * display,const gl::Context * context)186 Error ExternalImageSibling::initialize(const egl::Display *display, const gl::Context *context)
187 {
188     return mImplementation->initialize(display);
189 }
190 
getAttachmentSize(const gl::ImageIndex & imageIndex) const191 gl::Extents ExternalImageSibling::getAttachmentSize(const gl::ImageIndex &imageIndex) const
192 {
193     return mImplementation->getSize();
194 }
195 
getAttachmentFormat(GLenum binding,const gl::ImageIndex & imageIndex) const196 gl::Format ExternalImageSibling::getAttachmentFormat(GLenum binding,
197                                                      const gl::ImageIndex &imageIndex) const
198 {
199     return mImplementation->getFormat();
200 }
201 
getAttachmentSamples(const gl::ImageIndex & imageIndex) const202 GLsizei ExternalImageSibling::getAttachmentSamples(const gl::ImageIndex &imageIndex) const
203 {
204     return static_cast<GLsizei>(mImplementation->getSamples());
205 }
206 
getLevelCount() const207 GLuint ExternalImageSibling::getLevelCount() const
208 {
209     return static_cast<GLuint>(mImplementation->getLevelCount());
210 }
211 
isRenderable(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex) const212 bool ExternalImageSibling::isRenderable(const gl::Context *context,
213                                         GLenum binding,
214                                         const gl::ImageIndex &imageIndex) const
215 {
216     return mImplementation->isRenderable(context);
217 }
218 
isTextureable(const gl::Context * context) const219 bool ExternalImageSibling::isTextureable(const gl::Context *context) const
220 {
221     return mImplementation->isTexturable(context);
222 }
223 
isYUV() const224 bool ExternalImageSibling::isYUV() const
225 {
226     return mImplementation->isYUV();
227 }
228 
hasFrontBufferUsage() const229 bool ExternalImageSibling::hasFrontBufferUsage() const
230 {
231     return mImplementation->hasFrontBufferUsage();
232 }
233 
isCubeMap() const234 bool ExternalImageSibling::isCubeMap() const
235 {
236     return mImplementation->isCubeMap();
237 }
238 
hasProtectedContent() const239 bool ExternalImageSibling::hasProtectedContent() const
240 {
241     return mImplementation->hasProtectedContent();
242 }
243 
onAttach(const gl::Context * context,rx::UniqueSerial framebufferSerial)244 void ExternalImageSibling::onAttach(const gl::Context *context, rx::UniqueSerial framebufferSerial)
245 {}
246 
onDetach(const gl::Context * context,rx::UniqueSerial framebufferSerial)247 void ExternalImageSibling::onDetach(const gl::Context *context, rx::UniqueSerial framebufferSerial)
248 {}
249 
getId() const250 GLuint ExternalImageSibling::getId() const
251 {
252     UNREACHABLE();
253     return 0;
254 }
255 
initState(GLenum binding,const gl::ImageIndex & imageIndex) const256 gl::InitState ExternalImageSibling::initState(GLenum binding,
257                                               const gl::ImageIndex &imageIndex) const
258 {
259     return gl::InitState::Initialized;
260 }
261 
setInitState(GLenum binding,const gl::ImageIndex & imageIndex,gl::InitState initState)262 void ExternalImageSibling::setInitState(GLenum binding,
263                                         const gl::ImageIndex &imageIndex,
264                                         gl::InitState initState)
265 {}
266 
getImplementation() const267 rx::ExternalImageSiblingImpl *ExternalImageSibling::getImplementation() const
268 {
269     return mImplementation.get();
270 }
271 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)272 void ExternalImageSibling::onSubjectStateChange(angle::SubjectIndex index,
273                                                 angle::SubjectMessage message)
274 {
275     onStateChange(message);
276 }
277 
getAttachmentImpl() const278 rx::FramebufferAttachmentObjectImpl *ExternalImageSibling::getAttachmentImpl() const
279 {
280     return mImplementation.get();
281 }
282 
ImageState(ImageID id,EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)283 ImageState::ImageState(ImageID id,
284                        EGLenum target,
285                        ImageSibling *buffer,
286                        const AttributeMap &attribs)
287     : id(id),
288       label(nullptr),
289       target(target),
290       imageIndex(GetImageIndex(target, attribs)),
291       source(buffer),
292       format(GL_NONE),
293       yuv(false),
294       cubeMap(false),
295       size(),
296       samples(),
297       levelCount(1),
298       colorspace(
299           static_cast<EGLenum>(attribs.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_DEFAULT_EXT))),
300       hasProtectedContent(static_cast<bool>(attribs.get(EGL_PROTECTED_CONTENT_EXT, EGL_FALSE)))
301 {}
302 
~ImageState()303 ImageState::~ImageState() {}
304 
Image(rx::EGLImplFactory * factory,ImageID id,const gl::Context * context,EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)305 Image::Image(rx::EGLImplFactory *factory,
306              ImageID id,
307              const gl::Context *context,
308              EGLenum target,
309              ImageSibling *buffer,
310              const AttributeMap &attribs)
311     : mState(id, target, buffer, attribs),
312       mImplementation(factory->createImage(mState, context, target, attribs)),
313       mOrphanedAndNeedsInit(false),
314       mContextMutex(nullptr)
315 {
316     ASSERT(mImplementation != nullptr);
317     ASSERT(buffer != nullptr);
318 
319     if (kIsContextMutexEnabled)
320     {
321         if (context != nullptr)
322         {
323             mContextMutex = context->getContextMutex().getRoot();
324             ASSERT(mContextMutex->isReferenced());
325         }
326         else
327         {
328             mContextMutex = new ContextMutex();
329         }
330         mContextMutex->addRef();
331     }
332 
333     mState.source->addImageSource(this);
334 }
335 
onDestroy(const Display * display)336 void Image::onDestroy(const Display *display)
337 {
338     // All targets should hold a ref to the egl image and it should not be deleted until there are
339     // no siblings left.
340     ASSERT([&] {
341         std::unique_lock lock(mState.targetsLock);
342         return mState.targets.empty();
343     }());
344 
345     // Make sure the implementation gets a chance to clean up before we delete the source.
346     mImplementation->onDestroy(display);
347 
348     // Tell the source that it is no longer used by this image
349     if (mState.source != nullptr)
350     {
351         mState.source->removeImageSource(this);
352 
353         // If the source is an external object, delete it
354         if (IsExternalImageTarget(mState.target))
355         {
356             ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
357             externalSibling->onDestroy(display);
358             delete externalSibling;
359         }
360 
361         mState.source = nullptr;
362     }
363 }
364 
~Image()365 Image::~Image()
366 {
367     SafeDelete(mImplementation);
368 
369     if (mContextMutex != nullptr)
370     {
371         mContextMutex->release();
372         mContextMutex = nullptr;
373     }
374 }
375 
setLabel(EGLLabelKHR label)376 void Image::setLabel(EGLLabelKHR label)
377 {
378     mState.label = label;
379 }
380 
getLabel() const381 EGLLabelKHR Image::getLabel() const
382 {
383     return mState.label;
384 }
385 
addTargetSibling(ImageSibling * sibling)386 void Image::addTargetSibling(ImageSibling *sibling)
387 {
388     std::unique_lock lock(mState.targetsLock);
389     mState.targets.insert(sibling);
390 }
391 
orphanSibling(const gl::Context * context,ImageSibling * sibling)392 angle::Result Image::orphanSibling(const gl::Context *context, ImageSibling *sibling)
393 {
394     ASSERT(sibling != nullptr);
395 
396     // notify impl
397     ANGLE_TRY(mImplementation->orphan(context, sibling));
398 
399     if (mState.source == sibling)
400     {
401         // The external source of an image cannot be redefined so it cannot be orphaned.
402         ASSERT(!IsExternalImageTarget(mState.target));
403 
404         // If the sibling is the source, it cannot be a target.
405         ASSERT([&] {
406             std::unique_lock lock(mState.targetsLock);
407             return mState.targets.find(sibling) == mState.targets.end();
408         }());
409         mState.source = nullptr;
410         mOrphanedAndNeedsInit =
411             (sibling->initState(GL_NONE, mState.imageIndex) == gl::InitState::MayNeedInit);
412     }
413     else
414     {
415         std::unique_lock lock(mState.targetsLock);
416         mState.targets.erase(sibling);
417     }
418 
419     return angle::Result::Continue;
420 }
421 
getFormat() const422 const gl::Format &Image::getFormat() const
423 {
424     return mState.format;
425 }
426 
isRenderable(const gl::Context * context) const427 bool Image::isRenderable(const gl::Context *context) const
428 {
429     return mIsRenderable;
430 }
431 
isTexturable(const gl::Context * context) const432 bool Image::isTexturable(const gl::Context *context) const
433 {
434     return mIsTexturable;
435 }
436 
isYUV() const437 bool Image::isYUV() const
438 {
439     return mState.yuv;
440 }
441 
isExternalImageWithoutIndividualSync() const442 bool Image::isExternalImageWithoutIndividualSync() const
443 {
444     // Only Vulkan images are individually synced.
445     return IsExternalImageTarget(mState.target) && mState.target != EGL_VULKAN_IMAGE_ANGLE;
446 }
447 
hasFrontBufferUsage() const448 bool Image::hasFrontBufferUsage() const
449 {
450     if (IsExternalImageTarget(mState.target))
451     {
452         ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
453         return externalSibling->hasFrontBufferUsage();
454     }
455 
456     return false;
457 }
458 
isCubeMap() const459 bool Image::isCubeMap() const
460 {
461     return mState.cubeMap;
462 }
463 
getWidth() const464 size_t Image::getWidth() const
465 {
466     return mState.size.width;
467 }
468 
getHeight() const469 size_t Image::getHeight() const
470 {
471     return mState.size.height;
472 }
473 
getExtents() const474 const gl::Extents &Image::getExtents() const
475 {
476     return mState.size;
477 }
478 
isLayered() const479 bool Image::isLayered() const
480 {
481     return mState.imageIndex.isLayered();
482 }
483 
getSamples() const484 size_t Image::getSamples() const
485 {
486     return mState.samples;
487 }
488 
getLevelCount() const489 GLuint Image::getLevelCount() const
490 {
491     return mState.levelCount;
492 }
493 
hasProtectedContent() const494 bool Image::hasProtectedContent() const
495 {
496     return mState.hasProtectedContent;
497 }
498 
isFixedRatedCompression(const gl::Context * context) const499 bool Image::isFixedRatedCompression(const gl::Context *context) const
500 {
501     return mImplementation->isFixedRatedCompression(context);
502 }
503 
getImplementation() const504 rx::ImageImpl *Image::getImplementation() const
505 {
506     return mImplementation;
507 }
508 
initialize(const Display * display,const gl::Context * context)509 Error Image::initialize(const Display *display, const gl::Context *context)
510 {
511     if (IsExternalImageTarget(mState.target))
512     {
513         ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
514         ANGLE_TRY(externalSibling->initialize(display, context));
515 
516         mState.hasProtectedContent = externalSibling->hasProtectedContent();
517         mState.levelCount          = externalSibling->getLevelCount();
518         mState.cubeMap             = externalSibling->isCubeMap();
519 
520         // External siblings can be YUV
521         mState.yuv = externalSibling->isYUV();
522     }
523 
524     mState.format = mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex);
525 
526     if (mState.colorspace != EGL_GL_COLORSPACE_DEFAULT_EXT)
527     {
528         GLenum nonLinearFormat = mState.format.info->sizedInternalFormat;
529         if (!gl::ColorspaceFormatOverride(mState.colorspace, &nonLinearFormat))
530         {
531             // the colorspace format is not supported
532             return egl::EglBadMatch();
533         }
534         mState.format = gl::Format(nonLinearFormat);
535     }
536 
537     if (!IsExternalImageTarget(mState.target))
538     {
539         // Account for the fact that GL_ANGLE_yuv_internal_format extension maybe enabled,
540         // in which case the internal format itself could be YUV.
541         mState.yuv = gl::IsYuvFormat(mState.format.info->sizedInternalFormat);
542     }
543 
544     mState.size    = mState.source->getAttachmentSize(mState.imageIndex);
545     mState.samples = mState.source->getAttachmentSamples(mState.imageIndex);
546 
547     if (IsTextureTarget(mState.target))
548     {
549         mState.size.depth = 1;
550     }
551 
552     Error error = mImplementation->initialize(display);
553     if (error.isError())
554     {
555         return error;
556     }
557 
558     if (IsTextureTarget(mState.target))
559     {
560         mIsTexturable = true;
561         mIsRenderable = mState.format.info->textureAttachmentSupport(context->getClientVersion(),
562                                                                      context->getExtensions());
563     }
564     else if (IsRenderbufferTarget(mState.target))
565     {
566         mIsTexturable = true;
567         mIsRenderable = mState.format.info->renderbufferSupport(context->getClientVersion(),
568                                                                 context->getExtensions());
569     }
570     else if (IsExternalImageTarget(mState.target))
571     {
572         ASSERT(mState.source != nullptr);
573         mIsTexturable = rx::GetAs<ExternalImageSibling>(mState.source)->isTextureable(context);
574         mIsRenderable = rx::GetAs<ExternalImageSibling>(mState.source)
575                             ->isRenderable(context, GL_NONE, gl::ImageIndex());
576     }
577     else
578     {
579         UNREACHABLE();
580     }
581 
582     return NoError();
583 }
584 
orphaned() const585 bool Image::orphaned() const
586 {
587     return (mState.source == nullptr);
588 }
589 
sourceInitState() const590 gl::InitState Image::sourceInitState() const
591 {
592     if (orphaned())
593     {
594         return mOrphanedAndNeedsInit ? gl::InitState::MayNeedInit : gl::InitState::Initialized;
595     }
596 
597     return mState.source->initState(GL_NONE, mState.imageIndex);
598 }
599 
setInitState(gl::InitState initState)600 void Image::setInitState(gl::InitState initState)
601 {
602     if (orphaned())
603     {
604         mOrphanedAndNeedsInit = false;
605     }
606 
607     return mState.source->setInitState(GL_NONE, mState.imageIndex, initState);
608 }
609 
exportVkImage(void * vkImage,void * vkImageCreateInfo)610 Error Image::exportVkImage(void *vkImage, void *vkImageCreateInfo)
611 {
612     return mImplementation->exportVkImage(vkImage, vkImageCreateInfo);
613 }
614 
notifySiblings(const ImageSibling * notifier,angle::SubjectMessage message)615 void Image::notifySiblings(const ImageSibling *notifier, angle::SubjectMessage message)
616 {
617     if (mState.source && mState.source != notifier)
618     {
619         mState.source->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
620     }
621 
622     std::unique_lock lock(mState.targetsLock);
623     for (ImageSibling *target : mState.targets)
624     {
625         if (target != notifier)
626         {
627             target->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
628         }
629     }
630 }
631 
632 }  // namespace egl
633