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 }  // anonymous namespace
53 
ImageSibling()54 ImageSibling::ImageSibling() : FramebufferAttachmentObject(), mSourcesOf(), mTargetOf() {}
55 
~ImageSibling()56 ImageSibling::~ImageSibling()
57 {
58     // EGL images should hold a ref to their targets and siblings, a Texture should not be deletable
59     // while it is attached to an EGL image.
60     // Child class should orphan images before destruction.
61     ASSERT(mSourcesOf.empty());
62     ASSERT(mTargetOf.get() == nullptr);
63 }
64 
setTargetImage(const gl::Context * context,egl::Image * imageTarget)65 void ImageSibling::setTargetImage(const gl::Context *context, egl::Image *imageTarget)
66 {
67     ASSERT(imageTarget != nullptr);
68     mTargetOf.set(DisplayFromContext(context), imageTarget);
69     imageTarget->addTargetSibling(this);
70 }
71 
orphanImages(const gl::Context * context)72 angle::Result ImageSibling::orphanImages(const gl::Context *context)
73 {
74     if (mTargetOf.get() != nullptr)
75     {
76         // Can't be a target and have sources.
77         ASSERT(mSourcesOf.empty());
78 
79         ANGLE_TRY(mTargetOf->orphanSibling(context, this));
80         mTargetOf.set(DisplayFromContext(context), nullptr);
81     }
82     else
83     {
84         for (Image *sourceImage : mSourcesOf)
85         {
86             ANGLE_TRY(sourceImage->orphanSibling(context, this));
87         }
88         mSourcesOf.clear();
89     }
90 
91     return angle::Result::Continue;
92 }
93 
addImageSource(egl::Image * imageSource)94 void ImageSibling::addImageSource(egl::Image *imageSource)
95 {
96     ASSERT(imageSource != nullptr);
97     mSourcesOf.insert(imageSource);
98 }
99 
removeImageSource(egl::Image * imageSource)100 void ImageSibling::removeImageSource(egl::Image *imageSource)
101 {
102     ASSERT(mSourcesOf.find(imageSource) != mSourcesOf.end());
103     mSourcesOf.erase(imageSource);
104 }
105 
isEGLImageTarget() const106 bool ImageSibling::isEGLImageTarget() const
107 {
108     return (mTargetOf.get() != nullptr);
109 }
110 
sourceEGLImageInitState() const111 gl::InitState ImageSibling::sourceEGLImageInitState() const
112 {
113     ASSERT(isEGLImageTarget());
114     return mTargetOf->sourceInitState();
115 }
116 
setSourceEGLImageInitState(gl::InitState initState) const117 void ImageSibling::setSourceEGLImageInitState(gl::InitState initState) const
118 {
119     ASSERT(isEGLImageTarget());
120     mTargetOf->setInitState(initState);
121 }
122 
isRenderable(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex) const123 bool ImageSibling::isRenderable(const gl::Context *context,
124                                 GLenum binding,
125                                 const gl::ImageIndex &imageIndex) const
126 {
127     ASSERT(isEGLImageTarget());
128     return mTargetOf->isRenderable(context);
129 }
130 
notifySiblings(angle::SubjectMessage message)131 void ImageSibling::notifySiblings(angle::SubjectMessage message)
132 {
133     if (mTargetOf.get())
134     {
135         mTargetOf->notifySiblings(this, message);
136     }
137     for (Image *source : mSourcesOf)
138     {
139         source->notifySiblings(this, message);
140     }
141 }
142 
ExternalImageSibling(rx::EGLImplFactory * factory,const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const AttributeMap & attribs)143 ExternalImageSibling::ExternalImageSibling(rx::EGLImplFactory *factory,
144                                            const gl::Context *context,
145                                            EGLenum target,
146                                            EGLClientBuffer buffer,
147                                            const AttributeMap &attribs)
148     : mImplementation(factory->createExternalImageSibling(context, target, buffer, attribs))
149 {}
150 
151 ExternalImageSibling::~ExternalImageSibling() = default;
152 
onDestroy(const egl::Display * display)153 void ExternalImageSibling::onDestroy(const egl::Display *display)
154 {
155     mImplementation->onDestroy(display);
156 }
157 
initialize(const egl::Display * display)158 Error ExternalImageSibling::initialize(const egl::Display *display)
159 {
160     return mImplementation->initialize(display);
161 }
162 
getAttachmentSize(const gl::ImageIndex & imageIndex) const163 gl::Extents ExternalImageSibling::getAttachmentSize(const gl::ImageIndex &imageIndex) const
164 {
165     return mImplementation->getSize();
166 }
167 
getAttachmentFormat(GLenum binding,const gl::ImageIndex & imageIndex) const168 gl::Format ExternalImageSibling::getAttachmentFormat(GLenum binding,
169                                                      const gl::ImageIndex &imageIndex) const
170 {
171     return mImplementation->getFormat();
172 }
173 
getAttachmentSamples(const gl::ImageIndex & imageIndex) const174 GLsizei ExternalImageSibling::getAttachmentSamples(const gl::ImageIndex &imageIndex) const
175 {
176     return static_cast<GLsizei>(mImplementation->getSamples());
177 }
178 
isRenderable(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex) const179 bool ExternalImageSibling::isRenderable(const gl::Context *context,
180                                         GLenum binding,
181                                         const gl::ImageIndex &imageIndex) const
182 {
183     return mImplementation->isRenderable(context);
184 }
185 
isTextureable(const gl::Context * context) const186 bool ExternalImageSibling::isTextureable(const gl::Context *context) const
187 {
188     return mImplementation->isTexturable(context);
189 }
190 
onAttach(const gl::Context * context)191 void ExternalImageSibling::onAttach(const gl::Context *context) {}
192 
onDetach(const gl::Context * context)193 void ExternalImageSibling::onDetach(const gl::Context *context) {}
194 
getId() const195 GLuint ExternalImageSibling::getId() const
196 {
197     UNREACHABLE();
198     return 0;
199 }
200 
initState(const gl::ImageIndex & imageIndex) const201 gl::InitState ExternalImageSibling::initState(const gl::ImageIndex &imageIndex) const
202 {
203     return gl::InitState::Initialized;
204 }
205 
setInitState(const gl::ImageIndex & imageIndex,gl::InitState initState)206 void ExternalImageSibling::setInitState(const gl::ImageIndex &imageIndex, gl::InitState initState)
207 {}
208 
getImplementation() const209 rx::ExternalImageSiblingImpl *ExternalImageSibling::getImplementation() const
210 {
211     return mImplementation.get();
212 }
213 
getAttachmentImpl() const214 rx::FramebufferAttachmentObjectImpl *ExternalImageSibling::getAttachmentImpl() const
215 {
216     return mImplementation.get();
217 }
218 
ImageState(EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)219 ImageState::ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs)
220     : label(nullptr),
221       target(target),
222       imageIndex(GetImageIndex(target, attribs)),
223       source(buffer),
224       targets(),
225       format(GL_NONE),
226       size(),
227       samples(),
228       sourceType(target)
229 {}
230 
~ImageState()231 ImageState::~ImageState() {}
232 
Image(rx::EGLImplFactory * factory,const gl::Context * context,EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)233 Image::Image(rx::EGLImplFactory *factory,
234              const gl::Context *context,
235              EGLenum target,
236              ImageSibling *buffer,
237              const AttributeMap &attribs)
238     : mState(target, buffer, attribs),
239       mImplementation(factory->createImage(mState, context, target, attribs)),
240       mOrphanedAndNeedsInit(false)
241 {
242     ASSERT(mImplementation != nullptr);
243     ASSERT(buffer != nullptr);
244 
245     mState.source->addImageSource(this);
246 }
247 
onDestroy(const Display * display)248 void Image::onDestroy(const Display *display)
249 {
250     // All targets should hold a ref to the egl image and it should not be deleted until there are
251     // no siblings left.
252     ASSERT(mState.targets.empty());
253 
254     // Make sure the implementation gets a chance to clean up before we delete the source.
255     mImplementation->onDestroy(display);
256 
257     // Tell the source that it is no longer used by this image
258     if (mState.source != nullptr)
259     {
260         mState.source->removeImageSource(this);
261 
262         // If the source is an external object, delete it
263         if (IsExternalImageTarget(mState.sourceType))
264         {
265             ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
266             externalSibling->onDestroy(display);
267             delete externalSibling;
268         }
269 
270         mState.source = nullptr;
271     }
272 }
273 
~Image()274 Image::~Image()
275 {
276     SafeDelete(mImplementation);
277 }
278 
setLabel(EGLLabelKHR label)279 void Image::setLabel(EGLLabelKHR label)
280 {
281     mState.label = label;
282 }
283 
getLabel() const284 EGLLabelKHR Image::getLabel() const
285 {
286     return mState.label;
287 }
288 
addTargetSibling(ImageSibling * sibling)289 void Image::addTargetSibling(ImageSibling *sibling)
290 {
291     mState.targets.insert(sibling);
292 }
293 
orphanSibling(const gl::Context * context,ImageSibling * sibling)294 angle::Result Image::orphanSibling(const gl::Context *context, ImageSibling *sibling)
295 {
296     ASSERT(sibling != nullptr);
297 
298     // notify impl
299     ANGLE_TRY(mImplementation->orphan(context, sibling));
300 
301     if (mState.source == sibling)
302     {
303         // The external source of an image cannot be redefined so it cannot be orpahend.
304         ASSERT(!IsExternalImageTarget(mState.sourceType));
305 
306         // If the sibling is the source, it cannot be a target.
307         ASSERT(mState.targets.find(sibling) == mState.targets.end());
308         mState.source = nullptr;
309         mOrphanedAndNeedsInit =
310             (sibling->initState(mState.imageIndex) == gl::InitState::MayNeedInit);
311     }
312     else
313     {
314         mState.targets.erase(sibling);
315     }
316 
317     return angle::Result::Continue;
318 }
319 
getFormat() const320 const gl::Format &Image::getFormat() const
321 {
322     return mState.format;
323 }
324 
isRenderable(const gl::Context * context) const325 bool Image::isRenderable(const gl::Context *context) const
326 {
327     if (IsTextureTarget(mState.sourceType))
328     {
329         return mState.format.info->textureAttachmentSupport(context->getClientVersion(),
330                                                             context->getExtensions());
331     }
332     else if (IsRenderbufferTarget(mState.sourceType))
333     {
334         return mState.format.info->renderbufferSupport(context->getClientVersion(),
335                                                        context->getExtensions());
336     }
337     else if (IsExternalImageTarget(mState.sourceType))
338     {
339         ASSERT(mState.source != nullptr);
340         return mState.source->isRenderable(context, GL_NONE, gl::ImageIndex());
341     }
342 
343     UNREACHABLE();
344     return false;
345 }
346 
isTexturable(const gl::Context * context) const347 bool Image::isTexturable(const gl::Context *context) const
348 {
349     if (IsTextureTarget(mState.sourceType))
350     {
351         return mState.format.info->textureSupport(context->getClientVersion(),
352                                                   context->getExtensions());
353     }
354     else if (IsRenderbufferTarget(mState.sourceType))
355     {
356         return true;
357     }
358     else if (IsExternalImageTarget(mState.sourceType))
359     {
360         ASSERT(mState.source != nullptr);
361         return rx::GetAs<ExternalImageSibling>(mState.source)->isTextureable(context);
362     }
363 
364     UNREACHABLE();
365     return false;
366 }
367 
getWidth() const368 size_t Image::getWidth() const
369 {
370     return mState.size.width;
371 }
372 
getHeight() const373 size_t Image::getHeight() const
374 {
375     return mState.size.height;
376 }
377 
getSamples() const378 size_t Image::getSamples() const
379 {
380     return mState.samples;
381 }
382 
getImplementation() const383 rx::ImageImpl *Image::getImplementation() const
384 {
385     return mImplementation;
386 }
387 
initialize(const Display * display)388 Error Image::initialize(const Display *display)
389 {
390     if (IsExternalImageTarget(mState.sourceType))
391     {
392         ANGLE_TRY(rx::GetAs<ExternalImageSibling>(mState.source)->initialize(display));
393     }
394 
395     mState.format  = mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex);
396     mState.size    = mState.source->getAttachmentSize(mState.imageIndex);
397     mState.samples = mState.source->getAttachmentSamples(mState.imageIndex);
398 
399     return mImplementation->initialize(display);
400 }
401 
orphaned() const402 bool Image::orphaned() const
403 {
404     return (mState.source == nullptr);
405 }
406 
sourceInitState() const407 gl::InitState Image::sourceInitState() const
408 {
409     if (orphaned())
410     {
411         return mOrphanedAndNeedsInit ? gl::InitState::MayNeedInit : gl::InitState::Initialized;
412     }
413 
414     return mState.source->initState(mState.imageIndex);
415 }
416 
setInitState(gl::InitState initState)417 void Image::setInitState(gl::InitState initState)
418 {
419     if (orphaned())
420     {
421         mOrphanedAndNeedsInit = false;
422     }
423 
424     return mState.source->setInitState(mState.imageIndex, initState);
425 }
426 
notifySiblings(const ImageSibling * notifier,angle::SubjectMessage message)427 void Image::notifySiblings(const ImageSibling *notifier, angle::SubjectMessage message)
428 {
429     if (mState.source && mState.source != notifier)
430     {
431         mState.source->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
432     }
433 
434     for (ImageSibling *target : mState.targets)
435     {
436         if (target != notifier)
437         {
438             target->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
439         }
440     }
441 }
442 
443 }  // namespace egl
444