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