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 if (gl::IsCubeMapFaceTarget(target))
42 {
43 return gl::ImageIndex::MakeCubeMapFace(target, mip);
44 }
45 else
46 {
47 ASSERT(layer == 0);
48 return gl::ImageIndex::MakeFromTarget(target, mip, 1);
49 }
50 }
51
DisplayFromContext(const gl::Context * context)52 const Display *DisplayFromContext(const gl::Context *context)
53 {
54 return (context ? context->getDisplay() : nullptr);
55 }
56
57 angle::SubjectIndex kExternalImageImplSubjectIndex = 0;
58 } // anonymous namespace
59
ImageSibling()60 ImageSibling::ImageSibling() : FramebufferAttachmentObject(), mSourcesOf(), mTargetOf() {}
61
~ImageSibling()62 ImageSibling::~ImageSibling()
63 {
64 // EGL images should hold a ref to their targets and siblings, a Texture should not be deletable
65 // while it is attached to an EGL image.
66 // Child class should orphan images before destruction.
67 ASSERT(mSourcesOf.empty());
68 ASSERT(mTargetOf.get() == nullptr);
69 }
70
setTargetImage(const gl::Context * context,egl::Image * imageTarget)71 void ImageSibling::setTargetImage(const gl::Context *context, egl::Image *imageTarget)
72 {
73 ASSERT(imageTarget != nullptr);
74 mTargetOf.set(DisplayFromContext(context), imageTarget);
75 imageTarget->addTargetSibling(this);
76 }
77
orphanImages(const gl::Context * context,RefCountObjectReleaser<Image> * outReleaseImage)78 angle::Result ImageSibling::orphanImages(const gl::Context *context,
79 RefCountObjectReleaser<Image> *outReleaseImage)
80 {
81 ASSERT(outReleaseImage != nullptr);
82
83 if (mTargetOf.get() != nullptr)
84 {
85 // Can't be a target and have sources.
86 ASSERT(mSourcesOf.empty());
87
88 ANGLE_TRY(mTargetOf->orphanSibling(context, this));
89 *outReleaseImage = mTargetOf.set(DisplayFromContext(context), nullptr);
90 }
91 else
92 {
93 for (Image *sourceImage : mSourcesOf)
94 {
95 ANGLE_TRY(sourceImage->orphanSibling(context, this));
96 }
97 mSourcesOf.clear();
98 }
99
100 return angle::Result::Continue;
101 }
102
addImageSource(egl::Image * imageSource)103 void ImageSibling::addImageSource(egl::Image *imageSource)
104 {
105 ASSERT(imageSource != nullptr);
106 mSourcesOf.insert(imageSource);
107 }
108
removeImageSource(egl::Image * imageSource)109 void ImageSibling::removeImageSource(egl::Image *imageSource)
110 {
111 ASSERT(mSourcesOf.find(imageSource) != mSourcesOf.end());
112 mSourcesOf.erase(imageSource);
113 }
114
isEGLImageTarget() const115 bool ImageSibling::isEGLImageTarget() const
116 {
117 return (mTargetOf.get() != nullptr);
118 }
119
sourceEGLImageInitState() const120 gl::InitState ImageSibling::sourceEGLImageInitState() const
121 {
122 ASSERT(isEGLImageTarget());
123 return mTargetOf->sourceInitState();
124 }
125
setSourceEGLImageInitState(gl::InitState initState) const126 void ImageSibling::setSourceEGLImageInitState(gl::InitState initState) const
127 {
128 ASSERT(isEGLImageTarget());
129 mTargetOf->setInitState(initState);
130 }
131
isAttachmentSpecified(const gl::ImageIndex & imageIndex) const132 bool ImageSibling::isAttachmentSpecified(const gl::ImageIndex &imageIndex) const
133 {
134 return !getAttachmentSize(imageIndex).empty();
135 }
136
isRenderable(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex) const137 bool ImageSibling::isRenderable(const gl::Context *context,
138 GLenum binding,
139 const gl::ImageIndex &imageIndex) const
140 {
141 ASSERT(isEGLImageTarget());
142 return mTargetOf->isRenderable(context);
143 }
144
isYUV() const145 bool ImageSibling::isYUV() const
146 {
147 return mTargetOf.get() && mTargetOf->isYUV();
148 }
149
isExternalImageWithoutIndividualSync() const150 bool ImageSibling::isExternalImageWithoutIndividualSync() const
151 {
152 return mTargetOf.get() && mTargetOf->isExternalImageWithoutIndividualSync();
153 }
154
hasFrontBufferUsage() const155 bool ImageSibling::hasFrontBufferUsage() const
156 {
157 return mTargetOf.get() && mTargetOf->hasFrontBufferUsage();
158 }
159
hasProtectedContent() const160 bool ImageSibling::hasProtectedContent() const
161 {
162 return mTargetOf.get() && mTargetOf->hasProtectedContent();
163 }
164
notifySiblings(angle::SubjectMessage message)165 void ImageSibling::notifySiblings(angle::SubjectMessage message)
166 {
167 if (mTargetOf.get())
168 {
169 mTargetOf->notifySiblings(this, message);
170 }
171 for (Image *source : mSourcesOf)
172 {
173 source->notifySiblings(this, message);
174 }
175 }
176
ExternalImageSibling(rx::EGLImplFactory * factory,const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const AttributeMap & attribs)177 ExternalImageSibling::ExternalImageSibling(rx::EGLImplFactory *factory,
178 const gl::Context *context,
179 EGLenum target,
180 EGLClientBuffer buffer,
181 const AttributeMap &attribs)
182 : mImplementation(factory->createExternalImageSibling(context, target, buffer, attribs)),
183 mImplObserverBinding(this, kExternalImageImplSubjectIndex)
184 {
185 mImplObserverBinding.bind(mImplementation.get());
186 }
187
188 ExternalImageSibling::~ExternalImageSibling() = default;
189
onDestroy(const egl::Display * display)190 void ExternalImageSibling::onDestroy(const egl::Display *display)
191 {
192 mImplementation->onDestroy(display);
193 }
194
initialize(const egl::Display * display,const gl::Context * context)195 Error ExternalImageSibling::initialize(const egl::Display *display, const gl::Context *context)
196 {
197 return mImplementation->initialize(display);
198 }
199
getAttachmentSize(const gl::ImageIndex & imageIndex) const200 gl::Extents ExternalImageSibling::getAttachmentSize(const gl::ImageIndex &imageIndex) const
201 {
202 return mImplementation->getSize();
203 }
204
getAttachmentFormat(GLenum binding,const gl::ImageIndex & imageIndex) const205 gl::Format ExternalImageSibling::getAttachmentFormat(GLenum binding,
206 const gl::ImageIndex &imageIndex) const
207 {
208 return mImplementation->getFormat();
209 }
210
getAttachmentSamples(const gl::ImageIndex & imageIndex) const211 GLsizei ExternalImageSibling::getAttachmentSamples(const gl::ImageIndex &imageIndex) const
212 {
213 return static_cast<GLsizei>(mImplementation->getSamples());
214 }
215
getLevelCount() const216 GLuint ExternalImageSibling::getLevelCount() const
217 {
218 return static_cast<GLuint>(mImplementation->getLevelCount());
219 }
220
isRenderable(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex) const221 bool ExternalImageSibling::isRenderable(const gl::Context *context,
222 GLenum binding,
223 const gl::ImageIndex &imageIndex) const
224 {
225 return mImplementation->isRenderable(context);
226 }
227
isTextureable(const gl::Context * context) const228 bool ExternalImageSibling::isTextureable(const gl::Context *context) const
229 {
230 return mImplementation->isTexturable(context);
231 }
232
isYUV() const233 bool ExternalImageSibling::isYUV() const
234 {
235 return mImplementation->isYUV();
236 }
237
hasFrontBufferUsage() const238 bool ExternalImageSibling::hasFrontBufferUsage() const
239 {
240 return mImplementation->hasFrontBufferUsage();
241 }
242
isCubeMap() const243 bool ExternalImageSibling::isCubeMap() const
244 {
245 return mImplementation->isCubeMap();
246 }
247
hasProtectedContent() const248 bool ExternalImageSibling::hasProtectedContent() const
249 {
250 return mImplementation->hasProtectedContent();
251 }
252
onAttach(const gl::Context * context,rx::UniqueSerial framebufferSerial)253 void ExternalImageSibling::onAttach(const gl::Context *context, rx::UniqueSerial framebufferSerial)
254 {}
255
onDetach(const gl::Context * context,rx::UniqueSerial framebufferSerial)256 void ExternalImageSibling::onDetach(const gl::Context *context, rx::UniqueSerial framebufferSerial)
257 {}
258
getId() const259 GLuint ExternalImageSibling::getId() const
260 {
261 UNREACHABLE();
262 return 0;
263 }
264
initState(GLenum binding,const gl::ImageIndex & imageIndex) const265 gl::InitState ExternalImageSibling::initState(GLenum binding,
266 const gl::ImageIndex &imageIndex) const
267 {
268 return gl::InitState::Initialized;
269 }
270
setInitState(GLenum binding,const gl::ImageIndex & imageIndex,gl::InitState initState)271 void ExternalImageSibling::setInitState(GLenum binding,
272 const gl::ImageIndex &imageIndex,
273 gl::InitState initState)
274 {}
275
getImplementation() const276 rx::ExternalImageSiblingImpl *ExternalImageSibling::getImplementation() const
277 {
278 return mImplementation.get();
279 }
280
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)281 void ExternalImageSibling::onSubjectStateChange(angle::SubjectIndex index,
282 angle::SubjectMessage message)
283 {
284 onStateChange(message);
285 }
286
getAttachmentImpl() const287 rx::FramebufferAttachmentObjectImpl *ExternalImageSibling::getAttachmentImpl() const
288 {
289 return mImplementation.get();
290 }
291
ImageState(ImageID id,EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)292 ImageState::ImageState(ImageID id,
293 EGLenum target,
294 ImageSibling *buffer,
295 const AttributeMap &attribs)
296 : id(id),
297 label(nullptr),
298 target(target),
299 imageIndex(GetImageIndex(target, attribs)),
300 source(buffer),
301 format(GL_NONE),
302 yuv(false),
303 cubeMap(false),
304 size(),
305 samples(),
306 levelCount(1),
307 colorspace(
308 static_cast<EGLenum>(attribs.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_DEFAULT_EXT))),
309 hasProtectedContent(static_cast<bool>(attribs.get(EGL_PROTECTED_CONTENT_EXT, EGL_FALSE)))
310 {}
311
~ImageState()312 ImageState::~ImageState() {}
313
Image(rx::EGLImplFactory * factory,ImageID id,const gl::Context * context,EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)314 Image::Image(rx::EGLImplFactory *factory,
315 ImageID id,
316 const gl::Context *context,
317 EGLenum target,
318 ImageSibling *buffer,
319 const AttributeMap &attribs)
320 : mState(id, target, buffer, attribs),
321 mImplementation(factory->createImage(mState, context, target, attribs)),
322 mOrphanedAndNeedsInit(false),
323 mContextMutex(nullptr)
324 {
325 ASSERT(mImplementation != nullptr);
326 ASSERT(buffer != nullptr);
327
328 if (kIsContextMutexEnabled)
329 {
330 if (context != nullptr)
331 {
332 mContextMutex = context->getContextMutex().getRoot();
333 ASSERT(mContextMutex->isReferenced());
334 }
335 else
336 {
337 mContextMutex = new ContextMutex();
338 }
339 mContextMutex->addRef();
340 }
341
342 mState.source->addImageSource(this);
343 }
344
onDestroy(const Display * display)345 void Image::onDestroy(const Display *display)
346 {
347 // All targets should hold a ref to the egl image and it should not be deleted until there are
348 // no siblings left.
349 ASSERT([&] {
350 std::unique_lock lock(mState.targetsLock);
351 return mState.targets.empty();
352 }());
353
354 // Make sure the implementation gets a chance to clean up before we delete the source.
355 mImplementation->onDestroy(display);
356
357 // Tell the source that it is no longer used by this image
358 if (mState.source != nullptr)
359 {
360 mState.source->removeImageSource(this);
361
362 // If the source is an external object, delete it
363 if (IsExternalImageTarget(mState.target))
364 {
365 ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
366 externalSibling->onDestroy(display);
367 delete externalSibling;
368 }
369
370 mState.source = nullptr;
371 }
372 }
373
~Image()374 Image::~Image()
375 {
376 SafeDelete(mImplementation);
377
378 if (mContextMutex != nullptr)
379 {
380 mContextMutex->release();
381 mContextMutex = nullptr;
382 }
383 }
384
setLabel(EGLLabelKHR label)385 void Image::setLabel(EGLLabelKHR label)
386 {
387 mState.label = label;
388 }
389
getLabel() const390 EGLLabelKHR Image::getLabel() const
391 {
392 return mState.label;
393 }
394
addTargetSibling(ImageSibling * sibling)395 void Image::addTargetSibling(ImageSibling *sibling)
396 {
397 std::unique_lock lock(mState.targetsLock);
398 mState.targets.insert(sibling);
399 }
400
orphanSibling(const gl::Context * context,ImageSibling * sibling)401 angle::Result Image::orphanSibling(const gl::Context *context, ImageSibling *sibling)
402 {
403 ASSERT(sibling != nullptr);
404
405 // notify impl
406 ANGLE_TRY(mImplementation->orphan(context, sibling));
407
408 if (mState.source == sibling)
409 {
410 // The external source of an image cannot be redefined so it cannot be orphaned.
411 ASSERT(!IsExternalImageTarget(mState.target));
412
413 // If the sibling is the source, it cannot be a target.
414 ASSERT([&] {
415 std::unique_lock lock(mState.targetsLock);
416 return mState.targets.find(sibling) == mState.targets.end();
417 }());
418 mState.source = nullptr;
419 mOrphanedAndNeedsInit =
420 (sibling->initState(GL_NONE, mState.imageIndex) == gl::InitState::MayNeedInit);
421 }
422 else
423 {
424 std::unique_lock lock(mState.targetsLock);
425 mState.targets.erase(sibling);
426 }
427
428 return angle::Result::Continue;
429 }
430
getFormat() const431 const gl::Format &Image::getFormat() const
432 {
433 return mState.format;
434 }
435
isRenderable(const gl::Context * context) const436 bool Image::isRenderable(const gl::Context *context) const
437 {
438 return mIsRenderable;
439 }
440
isTexturable(const gl::Context * context) const441 bool Image::isTexturable(const gl::Context *context) const
442 {
443 return mIsTexturable;
444 }
445
isYUV() const446 bool Image::isYUV() const
447 {
448 return mState.yuv;
449 }
450
isExternalImageWithoutIndividualSync() const451 bool Image::isExternalImageWithoutIndividualSync() const
452 {
453 // Only Vulkan images are individually synced.
454 return IsExternalImageTarget(mState.target) && mState.target != EGL_VULKAN_IMAGE_ANGLE;
455 }
456
hasFrontBufferUsage() const457 bool Image::hasFrontBufferUsage() const
458 {
459 if (IsExternalImageTarget(mState.target))
460 {
461 ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
462 return externalSibling->hasFrontBufferUsage();
463 }
464
465 return false;
466 }
467
isCubeMap() const468 bool Image::isCubeMap() const
469 {
470 return mState.cubeMap;
471 }
472
getWidth() const473 size_t Image::getWidth() const
474 {
475 return mState.size.width;
476 }
477
getHeight() const478 size_t Image::getHeight() const
479 {
480 return mState.size.height;
481 }
482
getExtents() const483 const gl::Extents &Image::getExtents() const
484 {
485 return mState.size;
486 }
487
isLayered() const488 bool Image::isLayered() const
489 {
490 return mState.imageIndex.isLayered();
491 }
492
getSamples() const493 size_t Image::getSamples() const
494 {
495 return mState.samples;
496 }
497
getLevelCount() const498 GLuint Image::getLevelCount() const
499 {
500 return mState.levelCount;
501 }
502
hasProtectedContent() const503 bool Image::hasProtectedContent() const
504 {
505 return mState.hasProtectedContent;
506 }
507
isFixedRatedCompression(const gl::Context * context) const508 bool Image::isFixedRatedCompression(const gl::Context *context) const
509 {
510 return mImplementation->isFixedRatedCompression(context);
511 }
512
getImplementation() const513 rx::ImageImpl *Image::getImplementation() const
514 {
515 return mImplementation;
516 }
517
initialize(const Display * display,const gl::Context * context)518 Error Image::initialize(const Display *display, const gl::Context *context)
519 {
520 if (IsExternalImageTarget(mState.target))
521 {
522 ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
523 ANGLE_TRY(externalSibling->initialize(display, context));
524
525 mState.hasProtectedContent = externalSibling->hasProtectedContent();
526 mState.levelCount = externalSibling->getLevelCount();
527 mState.cubeMap = externalSibling->isCubeMap();
528
529 // External siblings can be YUV
530 mState.yuv = externalSibling->isYUV();
531 }
532
533 mState.format = mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex);
534
535 if (mState.colorspace != EGL_GL_COLORSPACE_DEFAULT_EXT)
536 {
537 GLenum nonLinearFormat = mState.format.info->sizedInternalFormat;
538 if (!gl::ColorspaceFormatOverride(mState.colorspace, &nonLinearFormat))
539 {
540 // the colorspace format is not supported
541 return egl::Error(EGL_BAD_MATCH);
542 }
543 mState.format = gl::Format(nonLinearFormat);
544 }
545
546 if (!IsExternalImageTarget(mState.target))
547 {
548 // Account for the fact that GL_ANGLE_yuv_internal_format extension maybe enabled,
549 // in which case the internal format itself could be YUV.
550 mState.yuv = gl::IsYuvFormat(mState.format.info->sizedInternalFormat);
551 }
552
553 mState.size = mState.source->getAttachmentSize(mState.imageIndex);
554 mState.samples = mState.source->getAttachmentSamples(mState.imageIndex);
555
556 if (IsTextureTarget(mState.target))
557 {
558 mState.size.depth = 1;
559 }
560
561 Error error = mImplementation->initialize(display);
562 if (error.isError())
563 {
564 return error;
565 }
566
567 if (IsTextureTarget(mState.target))
568 {
569 mIsTexturable = true;
570 mIsRenderable = mState.format.info->textureAttachmentSupport(context->getClientVersion(),
571 context->getExtensions());
572 }
573 else if (IsRenderbufferTarget(mState.target))
574 {
575 mIsTexturable = true;
576 mIsRenderable = mState.format.info->renderbufferSupport(context->getClientVersion(),
577 context->getExtensions());
578 }
579 else if (IsExternalImageTarget(mState.target))
580 {
581 ASSERT(mState.source != nullptr);
582 mIsTexturable = rx::GetAs<ExternalImageSibling>(mState.source)->isTextureable(context);
583 mIsRenderable = rx::GetAs<ExternalImageSibling>(mState.source)
584 ->isRenderable(context, GL_NONE, gl::ImageIndex());
585 }
586 else
587 {
588 UNREACHABLE();
589 }
590
591 return NoError();
592 }
593
orphaned() const594 bool Image::orphaned() const
595 {
596 return (mState.source == nullptr);
597 }
598
sourceInitState() const599 gl::InitState Image::sourceInitState() const
600 {
601 if (orphaned())
602 {
603 return mOrphanedAndNeedsInit ? gl::InitState::MayNeedInit : gl::InitState::Initialized;
604 }
605
606 return mState.source->initState(GL_NONE, mState.imageIndex);
607 }
608
setInitState(gl::InitState initState)609 void Image::setInitState(gl::InitState initState)
610 {
611 if (orphaned())
612 {
613 mOrphanedAndNeedsInit = false;
614 }
615
616 return mState.source->setInitState(GL_NONE, mState.imageIndex, initState);
617 }
618
exportVkImage(void * vkImage,void * vkImageCreateInfo)619 Error Image::exportVkImage(void *vkImage, void *vkImageCreateInfo)
620 {
621 return mImplementation->exportVkImage(vkImage, vkImageCreateInfo);
622 }
623
notifySiblings(const ImageSibling * notifier,angle::SubjectMessage message)624 void Image::notifySiblings(const ImageSibling *notifier, angle::SubjectMessage message)
625 {
626 if (mState.source && mState.source != notifier)
627 {
628 mState.source->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
629 }
630
631 std::unique_lock lock(mState.targetsLock);
632 for (ImageSibling *target : mState.targets)
633 {
634 if (target != notifier)
635 {
636 target->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
637 }
638 }
639 }
640
641 } // namespace egl
642