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)74 angle::Result ImageSibling::orphanImages(const gl::Context *context)
75 {
76     if (mTargetOf.get() != nullptr)
77     {
78         // Can't be a target and have sources.
79         ASSERT(mSourcesOf.empty());
80 
81         ANGLE_TRY(mTargetOf->orphanSibling(context, this));
82         mTargetOf.set(DisplayFromContext(context), nullptr);
83     }
84     else
85     {
86         for (Image *sourceImage : mSourcesOf)
87         {
88             ANGLE_TRY(sourceImage->orphanSibling(context, this));
89         }
90         mSourcesOf.clear();
91     }
92 
93     return angle::Result::Continue;
94 }
95 
addImageSource(egl::Image * imageSource)96 void ImageSibling::addImageSource(egl::Image *imageSource)
97 {
98     ASSERT(imageSource != nullptr);
99     mSourcesOf.insert(imageSource);
100 }
101 
removeImageSource(egl::Image * imageSource)102 void ImageSibling::removeImageSource(egl::Image *imageSource)
103 {
104     ASSERT(mSourcesOf.find(imageSource) != mSourcesOf.end());
105     mSourcesOf.erase(imageSource);
106 }
107 
isEGLImageTarget() const108 bool ImageSibling::isEGLImageTarget() const
109 {
110     return (mTargetOf.get() != nullptr);
111 }
112 
sourceEGLImageInitState() const113 gl::InitState ImageSibling::sourceEGLImageInitState() const
114 {
115     ASSERT(isEGLImageTarget());
116     return mTargetOf->sourceInitState();
117 }
118 
setSourceEGLImageInitState(gl::InitState initState) const119 void ImageSibling::setSourceEGLImageInitState(gl::InitState initState) const
120 {
121     ASSERT(isEGLImageTarget());
122     mTargetOf->setInitState(initState);
123 }
124 
isRenderable(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex) const125 bool ImageSibling::isRenderable(const gl::Context *context,
126                                 GLenum binding,
127                                 const gl::ImageIndex &imageIndex) const
128 {
129     ASSERT(isEGLImageTarget());
130     return mTargetOf->isRenderable(context);
131 }
132 
isYUV() const133 bool ImageSibling::isYUV() const
134 {
135     return mTargetOf.get() && mTargetOf->isYUV();
136 }
137 
notifySiblings(angle::SubjectMessage message)138 void ImageSibling::notifySiblings(angle::SubjectMessage message)
139 {
140     if (mTargetOf.get())
141     {
142         mTargetOf->notifySiblings(this, message);
143     }
144     for (Image *source : mSourcesOf)
145     {
146         source->notifySiblings(this, message);
147     }
148 }
149 
ExternalImageSibling(rx::EGLImplFactory * factory,const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const AttributeMap & attribs)150 ExternalImageSibling::ExternalImageSibling(rx::EGLImplFactory *factory,
151                                            const gl::Context *context,
152                                            EGLenum target,
153                                            EGLClientBuffer buffer,
154                                            const AttributeMap &attribs)
155     : mImplementation(factory->createExternalImageSibling(context, target, buffer, attribs)),
156       mImplObserverBinding(this, kExternalImageImplSubjectIndex)
157 {
158     mImplObserverBinding.bind(mImplementation.get());
159 }
160 
161 ExternalImageSibling::~ExternalImageSibling() = default;
162 
onDestroy(const egl::Display * display)163 void ExternalImageSibling::onDestroy(const egl::Display *display)
164 {
165     mImplementation->onDestroy(display);
166 }
167 
initialize(const egl::Display * display)168 Error ExternalImageSibling::initialize(const egl::Display *display)
169 {
170     return mImplementation->initialize(display);
171 }
172 
getAttachmentSize(const gl::ImageIndex & imageIndex) const173 gl::Extents ExternalImageSibling::getAttachmentSize(const gl::ImageIndex &imageIndex) const
174 {
175     return mImplementation->getSize();
176 }
177 
getAttachmentFormat(GLenum binding,const gl::ImageIndex & imageIndex) const178 gl::Format ExternalImageSibling::getAttachmentFormat(GLenum binding,
179                                                      const gl::ImageIndex &imageIndex) const
180 {
181     return mImplementation->getFormat();
182 }
183 
getAttachmentSamples(const gl::ImageIndex & imageIndex) const184 GLsizei ExternalImageSibling::getAttachmentSamples(const gl::ImageIndex &imageIndex) const
185 {
186     return static_cast<GLsizei>(mImplementation->getSamples());
187 }
188 
isRenderable(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex) const189 bool ExternalImageSibling::isRenderable(const gl::Context *context,
190                                         GLenum binding,
191                                         const gl::ImageIndex &imageIndex) const
192 {
193     return mImplementation->isRenderable(context);
194 }
195 
isTextureable(const gl::Context * context) const196 bool ExternalImageSibling::isTextureable(const gl::Context *context) const
197 {
198     return mImplementation->isTexturable(context);
199 }
200 
isYUV() const201 bool ExternalImageSibling::isYUV() const
202 {
203     return mImplementation->isYUV();
204 }
205 
onAttach(const gl::Context * context,rx::Serial framebufferSerial)206 void ExternalImageSibling::onAttach(const gl::Context *context, rx::Serial framebufferSerial) {}
207 
onDetach(const gl::Context * context,rx::Serial framebufferSerial)208 void ExternalImageSibling::onDetach(const gl::Context *context, rx::Serial framebufferSerial) {}
209 
getId() const210 GLuint ExternalImageSibling::getId() const
211 {
212     UNREACHABLE();
213     return 0;
214 }
215 
initState(const gl::ImageIndex & imageIndex) const216 gl::InitState ExternalImageSibling::initState(const gl::ImageIndex &imageIndex) const
217 {
218     return gl::InitState::Initialized;
219 }
220 
setInitState(const gl::ImageIndex & imageIndex,gl::InitState initState)221 void ExternalImageSibling::setInitState(const gl::ImageIndex &imageIndex, gl::InitState initState)
222 {}
223 
getImplementation() const224 rx::ExternalImageSiblingImpl *ExternalImageSibling::getImplementation() const
225 {
226     return mImplementation.get();
227 }
228 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)229 void ExternalImageSibling::onSubjectStateChange(angle::SubjectIndex index,
230                                                 angle::SubjectMessage message)
231 {
232     onStateChange(message);
233 }
234 
getAttachmentImpl() const235 rx::FramebufferAttachmentObjectImpl *ExternalImageSibling::getAttachmentImpl() const
236 {
237     return mImplementation.get();
238 }
239 
ImageState(EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)240 ImageState::ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs)
241     : label(nullptr),
242       target(target),
243       imageIndex(GetImageIndex(target, attribs)),
244       source(buffer),
245       targets(),
246       format(GL_NONE),
247       yuv(false),
248       size(),
249       samples(),
250       sourceType(target),
251       colorspace(
252           static_cast<EGLenum>(attribs.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_DEFAULT_EXT)))
253 {}
254 
~ImageState()255 ImageState::~ImageState() {}
256 
Image(rx::EGLImplFactory * factory,const gl::Context * context,EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)257 Image::Image(rx::EGLImplFactory *factory,
258              const gl::Context *context,
259              EGLenum target,
260              ImageSibling *buffer,
261              const AttributeMap &attribs)
262     : mState(target, buffer, attribs),
263       mImplementation(factory->createImage(mState, context, target, attribs)),
264       mOrphanedAndNeedsInit(false)
265 {
266     ASSERT(mImplementation != nullptr);
267     ASSERT(buffer != nullptr);
268 
269     mState.source->addImageSource(this);
270 }
271 
onDestroy(const Display * display)272 void Image::onDestroy(const Display *display)
273 {
274     // All targets should hold a ref to the egl image and it should not be deleted until there are
275     // no siblings left.
276     ASSERT(mState.targets.empty());
277 
278     // Make sure the implementation gets a chance to clean up before we delete the source.
279     mImplementation->onDestroy(display);
280 
281     // Tell the source that it is no longer used by this image
282     if (mState.source != nullptr)
283     {
284         mState.source->removeImageSource(this);
285 
286         // If the source is an external object, delete it
287         if (IsExternalImageTarget(mState.sourceType))
288         {
289             ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
290             externalSibling->onDestroy(display);
291             delete externalSibling;
292         }
293 
294         mState.source = nullptr;
295     }
296 }
297 
~Image()298 Image::~Image()
299 {
300     SafeDelete(mImplementation);
301 }
302 
setLabel(EGLLabelKHR label)303 void Image::setLabel(EGLLabelKHR label)
304 {
305     mState.label = label;
306 }
307 
getLabel() const308 EGLLabelKHR Image::getLabel() const
309 {
310     return mState.label;
311 }
312 
addTargetSibling(ImageSibling * sibling)313 void Image::addTargetSibling(ImageSibling *sibling)
314 {
315     mState.targets.insert(sibling);
316 }
317 
orphanSibling(const gl::Context * context,ImageSibling * sibling)318 angle::Result Image::orphanSibling(const gl::Context *context, ImageSibling *sibling)
319 {
320     ASSERT(sibling != nullptr);
321 
322     // notify impl
323     ANGLE_TRY(mImplementation->orphan(context, sibling));
324 
325     if (mState.source == sibling)
326     {
327         // The external source of an image cannot be redefined so it cannot be orpahend.
328         ASSERT(!IsExternalImageTarget(mState.sourceType));
329 
330         // If the sibling is the source, it cannot be a target.
331         ASSERT(mState.targets.find(sibling) == mState.targets.end());
332         mState.source = nullptr;
333         mOrphanedAndNeedsInit =
334             (sibling->initState(mState.imageIndex) == gl::InitState::MayNeedInit);
335     }
336     else
337     {
338         mState.targets.erase(sibling);
339     }
340 
341     return angle::Result::Continue;
342 }
343 
getFormat() const344 const gl::Format &Image::getFormat() const
345 {
346     return mState.format;
347 }
348 
isRenderable(const gl::Context * context) const349 bool Image::isRenderable(const gl::Context *context) const
350 {
351     if (IsTextureTarget(mState.sourceType))
352     {
353         return mState.format.info->textureAttachmentSupport(context->getClientVersion(),
354                                                             context->getExtensions());
355     }
356     else if (IsRenderbufferTarget(mState.sourceType))
357     {
358         return mState.format.info->renderbufferSupport(context->getClientVersion(),
359                                                        context->getExtensions());
360     }
361     else if (IsExternalImageTarget(mState.sourceType))
362     {
363         ASSERT(mState.source != nullptr);
364         return mState.source->isRenderable(context, GL_NONE, gl::ImageIndex());
365     }
366 
367     UNREACHABLE();
368     return false;
369 }
370 
isTexturable(const gl::Context * context) const371 bool Image::isTexturable(const gl::Context *context) const
372 {
373     if (IsTextureTarget(mState.sourceType))
374     {
375         return mState.format.info->textureSupport(context->getClientVersion(),
376                                                   context->getExtensions());
377     }
378     else if (IsRenderbufferTarget(mState.sourceType))
379     {
380         return true;
381     }
382     else if (IsExternalImageTarget(mState.sourceType))
383     {
384         ASSERT(mState.source != nullptr);
385         return rx::GetAs<ExternalImageSibling>(mState.source)->isTextureable(context);
386     }
387 
388     UNREACHABLE();
389     return false;
390 }
391 
isYUV() const392 bool Image::isYUV() const
393 {
394     return mState.yuv;
395 }
396 
getWidth() const397 size_t Image::getWidth() const
398 {
399     return mState.size.width;
400 }
401 
getHeight() const402 size_t Image::getHeight() const
403 {
404     return mState.size.height;
405 }
406 
isLayered() const407 bool Image::isLayered() const
408 {
409     return mState.imageIndex.isLayered();
410 }
411 
getSamples() const412 size_t Image::getSamples() const
413 {
414     return mState.samples;
415 }
416 
getImplementation() const417 rx::ImageImpl *Image::getImplementation() const
418 {
419     return mImplementation;
420 }
421 
initialize(const Display * display)422 Error Image::initialize(const Display *display)
423 {
424     if (IsExternalImageTarget(mState.sourceType))
425     {
426         ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
427         ANGLE_TRY(externalSibling->initialize(display));
428 
429         // Only external siblings can be YUV
430         mState.yuv = externalSibling->isYUV();
431     }
432 
433     mState.format = mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex);
434 
435     if (mState.colorspace != EGL_GL_COLORSPACE_DEFAULT_EXT)
436     {
437         GLenum nonLinearFormat = mState.format.info->sizedInternalFormat;
438         if (!gl::ColorspaceFormatOverride(mState.colorspace, &nonLinearFormat))
439         {
440             // the colorspace format is not supported
441             return egl::EglBadMatch();
442         }
443         mState.format = gl::Format(nonLinearFormat);
444     }
445 
446     mState.size    = mState.source->getAttachmentSize(mState.imageIndex);
447     mState.samples = mState.source->getAttachmentSamples(mState.imageIndex);
448 
449     return mImplementation->initialize(display);
450 }
451 
orphaned() const452 bool Image::orphaned() const
453 {
454     return (mState.source == nullptr);
455 }
456 
sourceInitState() const457 gl::InitState Image::sourceInitState() const
458 {
459     if (orphaned())
460     {
461         return mOrphanedAndNeedsInit ? gl::InitState::MayNeedInit : gl::InitState::Initialized;
462     }
463 
464     return mState.source->initState(mState.imageIndex);
465 }
466 
setInitState(gl::InitState initState)467 void Image::setInitState(gl::InitState initState)
468 {
469     if (orphaned())
470     {
471         mOrphanedAndNeedsInit = false;
472     }
473 
474     return mState.source->setInitState(mState.imageIndex, initState);
475 }
476 
notifySiblings(const ImageSibling * notifier,angle::SubjectMessage message)477 void Image::notifySiblings(const ImageSibling *notifier, angle::SubjectMessage message)
478 {
479     if (mState.source && mState.source != notifier)
480     {
481         mState.source->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
482     }
483 
484     for (ImageSibling *target : mState.targets)
485     {
486         if (target != notifier)
487         {
488             target->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
489         }
490     }
491 }
492 
493 }  // namespace egl
494