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
notifySiblings(angle::SubjectMessage message)133 void ImageSibling::notifySiblings(angle::SubjectMessage message)
134 {
135 if (mTargetOf.get())
136 {
137 mTargetOf->notifySiblings(this, message);
138 }
139 for (Image *source : mSourcesOf)
140 {
141 source->notifySiblings(this, message);
142 }
143 }
144
ExternalImageSibling(rx::EGLImplFactory * factory,const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const AttributeMap & attribs)145 ExternalImageSibling::ExternalImageSibling(rx::EGLImplFactory *factory,
146 const gl::Context *context,
147 EGLenum target,
148 EGLClientBuffer buffer,
149 const AttributeMap &attribs)
150 : mImplementation(factory->createExternalImageSibling(context, target, buffer, attribs)),
151 mImplObserverBinding(this, kExternalImageImplSubjectIndex)
152 {
153 mImplObserverBinding.bind(mImplementation.get());
154 }
155
156 ExternalImageSibling::~ExternalImageSibling() = default;
157
onDestroy(const egl::Display * display)158 void ExternalImageSibling::onDestroy(const egl::Display *display)
159 {
160 mImplementation->onDestroy(display);
161 }
162
initialize(const egl::Display * display)163 Error ExternalImageSibling::initialize(const egl::Display *display)
164 {
165 return mImplementation->initialize(display);
166 }
167
getAttachmentSize(const gl::ImageIndex & imageIndex) const168 gl::Extents ExternalImageSibling::getAttachmentSize(const gl::ImageIndex &imageIndex) const
169 {
170 return mImplementation->getSize();
171 }
172
getAttachmentFormat(GLenum binding,const gl::ImageIndex & imageIndex) const173 gl::Format ExternalImageSibling::getAttachmentFormat(GLenum binding,
174 const gl::ImageIndex &imageIndex) const
175 {
176 return mImplementation->getFormat();
177 }
178
getAttachmentSamples(const gl::ImageIndex & imageIndex) const179 GLsizei ExternalImageSibling::getAttachmentSamples(const gl::ImageIndex &imageIndex) const
180 {
181 return static_cast<GLsizei>(mImplementation->getSamples());
182 }
183
isRenderable(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex) const184 bool ExternalImageSibling::isRenderable(const gl::Context *context,
185 GLenum binding,
186 const gl::ImageIndex &imageIndex) const
187 {
188 return mImplementation->isRenderable(context);
189 }
190
isTextureable(const gl::Context * context) const191 bool ExternalImageSibling::isTextureable(const gl::Context *context) const
192 {
193 return mImplementation->isTexturable(context);
194 }
195
onAttach(const gl::Context * context)196 void ExternalImageSibling::onAttach(const gl::Context *context) {}
197
onDetach(const gl::Context * context)198 void ExternalImageSibling::onDetach(const gl::Context *context) {}
199
getId() const200 GLuint ExternalImageSibling::getId() const
201 {
202 UNREACHABLE();
203 return 0;
204 }
205
initState(const gl::ImageIndex & imageIndex) const206 gl::InitState ExternalImageSibling::initState(const gl::ImageIndex &imageIndex) const
207 {
208 return gl::InitState::Initialized;
209 }
210
setInitState(const gl::ImageIndex & imageIndex,gl::InitState initState)211 void ExternalImageSibling::setInitState(const gl::ImageIndex &imageIndex, gl::InitState initState)
212 {}
213
getImplementation() const214 rx::ExternalImageSiblingImpl *ExternalImageSibling::getImplementation() const
215 {
216 return mImplementation.get();
217 }
218
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)219 void ExternalImageSibling::onSubjectStateChange(angle::SubjectIndex index,
220 angle::SubjectMessage message)
221 {
222 onStateChange(message);
223 }
224
getAttachmentImpl() const225 rx::FramebufferAttachmentObjectImpl *ExternalImageSibling::getAttachmentImpl() const
226 {
227 return mImplementation.get();
228 }
229
ImageState(EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)230 ImageState::ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs)
231 : label(nullptr),
232 target(target),
233 imageIndex(GetImageIndex(target, attribs)),
234 source(buffer),
235 targets(),
236 format(GL_NONE),
237 size(),
238 samples(),
239 sourceType(target),
240 colorspace(
241 static_cast<EGLenum>(attribs.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_DEFAULT_EXT)))
242 {}
243
~ImageState()244 ImageState::~ImageState() {}
245
Image(rx::EGLImplFactory * factory,const gl::Context * context,EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)246 Image::Image(rx::EGLImplFactory *factory,
247 const gl::Context *context,
248 EGLenum target,
249 ImageSibling *buffer,
250 const AttributeMap &attribs)
251 : mState(target, buffer, attribs),
252 mImplementation(factory->createImage(mState, context, target, attribs)),
253 mOrphanedAndNeedsInit(false)
254 {
255 ASSERT(mImplementation != nullptr);
256 ASSERT(buffer != nullptr);
257
258 mState.source->addImageSource(this);
259 }
260
onDestroy(const Display * display)261 void Image::onDestroy(const Display *display)
262 {
263 // All targets should hold a ref to the egl image and it should not be deleted until there are
264 // no siblings left.
265 ASSERT(mState.targets.empty());
266
267 // Make sure the implementation gets a chance to clean up before we delete the source.
268 mImplementation->onDestroy(display);
269
270 // Tell the source that it is no longer used by this image
271 if (mState.source != nullptr)
272 {
273 mState.source->removeImageSource(this);
274
275 // If the source is an external object, delete it
276 if (IsExternalImageTarget(mState.sourceType))
277 {
278 ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
279 externalSibling->onDestroy(display);
280 delete externalSibling;
281 }
282
283 mState.source = nullptr;
284 }
285 }
286
~Image()287 Image::~Image()
288 {
289 SafeDelete(mImplementation);
290 }
291
setLabel(EGLLabelKHR label)292 void Image::setLabel(EGLLabelKHR label)
293 {
294 mState.label = label;
295 }
296
getLabel() const297 EGLLabelKHR Image::getLabel() const
298 {
299 return mState.label;
300 }
301
addTargetSibling(ImageSibling * sibling)302 void Image::addTargetSibling(ImageSibling *sibling)
303 {
304 mState.targets.insert(sibling);
305 }
306
orphanSibling(const gl::Context * context,ImageSibling * sibling)307 angle::Result Image::orphanSibling(const gl::Context *context, ImageSibling *sibling)
308 {
309 ASSERT(sibling != nullptr);
310
311 // notify impl
312 ANGLE_TRY(mImplementation->orphan(context, sibling));
313
314 if (mState.source == sibling)
315 {
316 // The external source of an image cannot be redefined so it cannot be orpahend.
317 ASSERT(!IsExternalImageTarget(mState.sourceType));
318
319 // If the sibling is the source, it cannot be a target.
320 ASSERT(mState.targets.find(sibling) == mState.targets.end());
321 mState.source = nullptr;
322 mOrphanedAndNeedsInit =
323 (sibling->initState(mState.imageIndex) == gl::InitState::MayNeedInit);
324 }
325 else
326 {
327 mState.targets.erase(sibling);
328 }
329
330 return angle::Result::Continue;
331 }
332
getFormat() const333 const gl::Format &Image::getFormat() const
334 {
335 return mState.format;
336 }
337
isRenderable(const gl::Context * context) const338 bool Image::isRenderable(const gl::Context *context) const
339 {
340 if (IsTextureTarget(mState.sourceType))
341 {
342 return mState.format.info->textureAttachmentSupport(context->getClientVersion(),
343 context->getExtensions());
344 }
345 else if (IsRenderbufferTarget(mState.sourceType))
346 {
347 return mState.format.info->renderbufferSupport(context->getClientVersion(),
348 context->getExtensions());
349 }
350 else if (IsExternalImageTarget(mState.sourceType))
351 {
352 ASSERT(mState.source != nullptr);
353 return mState.source->isRenderable(context, GL_NONE, gl::ImageIndex());
354 }
355
356 UNREACHABLE();
357 return false;
358 }
359
isTexturable(const gl::Context * context) const360 bool Image::isTexturable(const gl::Context *context) const
361 {
362 if (IsTextureTarget(mState.sourceType))
363 {
364 return mState.format.info->textureSupport(context->getClientVersion(),
365 context->getExtensions());
366 }
367 else if (IsRenderbufferTarget(mState.sourceType))
368 {
369 return true;
370 }
371 else if (IsExternalImageTarget(mState.sourceType))
372 {
373 ASSERT(mState.source != nullptr);
374 return rx::GetAs<ExternalImageSibling>(mState.source)->isTextureable(context);
375 }
376
377 UNREACHABLE();
378 return false;
379 }
380
getWidth() const381 size_t Image::getWidth() const
382 {
383 return mState.size.width;
384 }
385
getHeight() const386 size_t Image::getHeight() const
387 {
388 return mState.size.height;
389 }
390
isLayered() const391 bool Image::isLayered() const
392 {
393 return mState.imageIndex.isLayered();
394 }
395
getSamples() const396 size_t Image::getSamples() const
397 {
398 return mState.samples;
399 }
400
getImplementation() const401 rx::ImageImpl *Image::getImplementation() const
402 {
403 return mImplementation;
404 }
405
initialize(const Display * display)406 Error Image::initialize(const Display *display)
407 {
408 if (IsExternalImageTarget(mState.sourceType))
409 {
410 ANGLE_TRY(rx::GetAs<ExternalImageSibling>(mState.source)->initialize(display));
411 }
412
413 mState.format = mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex);
414
415 if (mState.colorspace != EGL_GL_COLORSPACE_DEFAULT_EXT)
416 {
417 GLenum nonLinearFormat = mState.format.info->sizedInternalFormat;
418 if (!gl::ColorspaceFormatOverride(mState.colorspace, &nonLinearFormat))
419 {
420 // the colorspace format is not supported
421 return egl::EglBadMatch();
422 }
423 mState.format = gl::Format(nonLinearFormat);
424 }
425
426 mState.size = mState.source->getAttachmentSize(mState.imageIndex);
427 mState.samples = mState.source->getAttachmentSamples(mState.imageIndex);
428
429 return mImplementation->initialize(display);
430 }
431
orphaned() const432 bool Image::orphaned() const
433 {
434 return (mState.source == nullptr);
435 }
436
sourceInitState() const437 gl::InitState Image::sourceInitState() const
438 {
439 if (orphaned())
440 {
441 return mOrphanedAndNeedsInit ? gl::InitState::MayNeedInit : gl::InitState::Initialized;
442 }
443
444 return mState.source->initState(mState.imageIndex);
445 }
446
setInitState(gl::InitState initState)447 void Image::setInitState(gl::InitState initState)
448 {
449 if (orphaned())
450 {
451 mOrphanedAndNeedsInit = false;
452 }
453
454 return mState.source->setInitState(mState.imageIndex, initState);
455 }
456
notifySiblings(const ImageSibling * notifier,angle::SubjectMessage message)457 void Image::notifySiblings(const ImageSibling *notifier, angle::SubjectMessage message)
458 {
459 if (mState.source && mState.source != notifier)
460 {
461 mState.source->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
462 }
463
464 for (ImageSibling *target : mState.targets)
465 {
466 if (target != notifier)
467 {
468 target->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
469 }
470 }
471 }
472
473 } // namespace egl
474