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