• 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 }  // 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       colorspace(
230           static_cast<EGLenum>(attribs.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_DEFAULT_EXT)))
231 {}
232 
~ImageState()233 ImageState::~ImageState() {}
234 
Image(rx::EGLImplFactory * factory,const gl::Context * context,EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)235 Image::Image(rx::EGLImplFactory *factory,
236              const gl::Context *context,
237              EGLenum target,
238              ImageSibling *buffer,
239              const AttributeMap &attribs)
240     : mState(target, buffer, attribs),
241       mImplementation(factory->createImage(mState, context, target, attribs)),
242       mOrphanedAndNeedsInit(false)
243 {
244     ASSERT(mImplementation != nullptr);
245     ASSERT(buffer != nullptr);
246 
247     mState.source->addImageSource(this);
248 }
249 
onDestroy(const Display * display)250 void Image::onDestroy(const Display *display)
251 {
252     // All targets should hold a ref to the egl image and it should not be deleted until there are
253     // no siblings left.
254     ASSERT(mState.targets.empty());
255 
256     // Make sure the implementation gets a chance to clean up before we delete the source.
257     mImplementation->onDestroy(display);
258 
259     // Tell the source that it is no longer used by this image
260     if (mState.source != nullptr)
261     {
262         mState.source->removeImageSource(this);
263 
264         // If the source is an external object, delete it
265         if (IsExternalImageTarget(mState.sourceType))
266         {
267             ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
268             externalSibling->onDestroy(display);
269             delete externalSibling;
270         }
271 
272         mState.source = nullptr;
273     }
274 }
275 
~Image()276 Image::~Image()
277 {
278     SafeDelete(mImplementation);
279 }
280 
setLabel(EGLLabelKHR label)281 void Image::setLabel(EGLLabelKHR label)
282 {
283     mState.label = label;
284 }
285 
getLabel() const286 EGLLabelKHR Image::getLabel() const
287 {
288     return mState.label;
289 }
290 
addTargetSibling(ImageSibling * sibling)291 void Image::addTargetSibling(ImageSibling *sibling)
292 {
293     mState.targets.insert(sibling);
294 }
295 
orphanSibling(const gl::Context * context,ImageSibling * sibling)296 angle::Result Image::orphanSibling(const gl::Context *context, ImageSibling *sibling)
297 {
298     ASSERT(sibling != nullptr);
299 
300     // notify impl
301     ANGLE_TRY(mImplementation->orphan(context, sibling));
302 
303     if (mState.source == sibling)
304     {
305         // The external source of an image cannot be redefined so it cannot be orpahend.
306         ASSERT(!IsExternalImageTarget(mState.sourceType));
307 
308         // If the sibling is the source, it cannot be a target.
309         ASSERT(mState.targets.find(sibling) == mState.targets.end());
310         mState.source = nullptr;
311         mOrphanedAndNeedsInit =
312             (sibling->initState(mState.imageIndex) == gl::InitState::MayNeedInit);
313     }
314     else
315     {
316         mState.targets.erase(sibling);
317     }
318 
319     return angle::Result::Continue;
320 }
321 
getFormat() const322 const gl::Format &Image::getFormat() const
323 {
324     return mState.format;
325 }
326 
isRenderable(const gl::Context * context) const327 bool Image::isRenderable(const gl::Context *context) const
328 {
329     if (IsTextureTarget(mState.sourceType))
330     {
331         return mState.format.info->textureAttachmentSupport(context->getClientVersion(),
332                                                             context->getExtensions());
333     }
334     else if (IsRenderbufferTarget(mState.sourceType))
335     {
336         return mState.format.info->renderbufferSupport(context->getClientVersion(),
337                                                        context->getExtensions());
338     }
339     else if (IsExternalImageTarget(mState.sourceType))
340     {
341         ASSERT(mState.source != nullptr);
342         return mState.source->isRenderable(context, GL_NONE, gl::ImageIndex());
343     }
344 
345     UNREACHABLE();
346     return false;
347 }
348 
isTexturable(const gl::Context * context) const349 bool Image::isTexturable(const gl::Context *context) const
350 {
351     if (IsTextureTarget(mState.sourceType))
352     {
353         return mState.format.info->textureSupport(context->getClientVersion(),
354                                                   context->getExtensions());
355     }
356     else if (IsRenderbufferTarget(mState.sourceType))
357     {
358         return true;
359     }
360     else if (IsExternalImageTarget(mState.sourceType))
361     {
362         ASSERT(mState.source != nullptr);
363         return rx::GetAs<ExternalImageSibling>(mState.source)->isTextureable(context);
364     }
365 
366     UNREACHABLE();
367     return false;
368 }
369 
getWidth() const370 size_t Image::getWidth() const
371 {
372     return mState.size.width;
373 }
374 
getHeight() const375 size_t Image::getHeight() const
376 {
377     return mState.size.height;
378 }
379 
getSamples() const380 size_t Image::getSamples() const
381 {
382     return mState.samples;
383 }
384 
getImplementation() const385 rx::ImageImpl *Image::getImplementation() const
386 {
387     return mImplementation;
388 }
389 
initialize(const Display * display)390 Error Image::initialize(const Display *display)
391 {
392     if (IsExternalImageTarget(mState.sourceType))
393     {
394         ANGLE_TRY(rx::GetAs<ExternalImageSibling>(mState.source)->initialize(display));
395     }
396 
397     mState.format = mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex);
398 
399     if (mState.colorspace != EGL_GL_COLORSPACE_DEFAULT_EXT)
400     {
401         GLenum nonLinearFormat = mState.format.info->sizedInternalFormat;
402         if (!gl::ColorspaceFormatOverride(mState.colorspace, &nonLinearFormat))
403         {
404             // the colorspace format is not supported
405             return egl::EglBadMatch();
406         }
407         mState.format = gl::Format(nonLinearFormat);
408     }
409 
410     mState.size    = mState.source->getAttachmentSize(mState.imageIndex);
411     mState.samples = mState.source->getAttachmentSamples(mState.imageIndex);
412 
413     return mImplementation->initialize(display);
414 }
415 
orphaned() const416 bool Image::orphaned() const
417 {
418     return (mState.source == nullptr);
419 }
420 
sourceInitState() const421 gl::InitState Image::sourceInitState() const
422 {
423     if (orphaned())
424     {
425         return mOrphanedAndNeedsInit ? gl::InitState::MayNeedInit : gl::InitState::Initialized;
426     }
427 
428     return mState.source->initState(mState.imageIndex);
429 }
430 
setInitState(gl::InitState initState)431 void Image::setInitState(gl::InitState initState)
432 {
433     if (orphaned())
434     {
435         mOrphanedAndNeedsInit = false;
436     }
437 
438     return mState.source->setInitState(mState.imageIndex, initState);
439 }
440 
notifySiblings(const ImageSibling * notifier,angle::SubjectMessage message)441 void Image::notifySiblings(const ImageSibling *notifier, angle::SubjectMessage message)
442 {
443     if (mState.source && mState.source != notifier)
444     {
445         mState.source->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
446     }
447 
448     for (ImageSibling *target : mState.targets)
449     {
450         if (target != notifier)
451         {
452             target->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
453         }
454     }
455 }
456 
457 }  // namespace egl
458