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
isExternalImageWithoutIndividualSync() const141 bool ImageSibling::isExternalImageWithoutIndividualSync() const
142 {
143 return mTargetOf.get() && mTargetOf->isExternalImageWithoutIndividualSync();
144 }
145
hasFrontBufferUsage() const146 bool ImageSibling::hasFrontBufferUsage() const
147 {
148 return mTargetOf.get() && mTargetOf->hasFrontBufferUsage();
149 }
150
hasProtectedContent() const151 bool ImageSibling::hasProtectedContent() const
152 {
153 return mTargetOf.get() && mTargetOf->hasProtectedContent();
154 }
155
notifySiblings(angle::SubjectMessage message)156 void ImageSibling::notifySiblings(angle::SubjectMessage message)
157 {
158 if (mTargetOf.get())
159 {
160 mTargetOf->notifySiblings(this, message);
161 }
162 for (Image *source : mSourcesOf)
163 {
164 source->notifySiblings(this, message);
165 }
166 }
167
ExternalImageSibling(rx::EGLImplFactory * factory,const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const AttributeMap & attribs)168 ExternalImageSibling::ExternalImageSibling(rx::EGLImplFactory *factory,
169 const gl::Context *context,
170 EGLenum target,
171 EGLClientBuffer buffer,
172 const AttributeMap &attribs)
173 : mImplementation(factory->createExternalImageSibling(context, target, buffer, attribs)),
174 mImplObserverBinding(this, kExternalImageImplSubjectIndex)
175 {
176 mImplObserverBinding.bind(mImplementation.get());
177 }
178
179 ExternalImageSibling::~ExternalImageSibling() = default;
180
onDestroy(const egl::Display * display)181 void ExternalImageSibling::onDestroy(const egl::Display *display)
182 {
183 mImplementation->onDestroy(display);
184 }
185
initialize(const egl::Display * display,const gl::Context * context)186 Error ExternalImageSibling::initialize(const egl::Display *display, const gl::Context *context)
187 {
188 return mImplementation->initialize(display);
189 }
190
getAttachmentSize(const gl::ImageIndex & imageIndex) const191 gl::Extents ExternalImageSibling::getAttachmentSize(const gl::ImageIndex &imageIndex) const
192 {
193 return mImplementation->getSize();
194 }
195
getAttachmentFormat(GLenum binding,const gl::ImageIndex & imageIndex) const196 gl::Format ExternalImageSibling::getAttachmentFormat(GLenum binding,
197 const gl::ImageIndex &imageIndex) const
198 {
199 return mImplementation->getFormat();
200 }
201
getAttachmentSamples(const gl::ImageIndex & imageIndex) const202 GLsizei ExternalImageSibling::getAttachmentSamples(const gl::ImageIndex &imageIndex) const
203 {
204 return static_cast<GLsizei>(mImplementation->getSamples());
205 }
206
getLevelCount() const207 GLuint ExternalImageSibling::getLevelCount() const
208 {
209 return static_cast<GLuint>(mImplementation->getLevelCount());
210 }
211
isRenderable(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex) const212 bool ExternalImageSibling::isRenderable(const gl::Context *context,
213 GLenum binding,
214 const gl::ImageIndex &imageIndex) const
215 {
216 return mImplementation->isRenderable(context);
217 }
218
isTextureable(const gl::Context * context) const219 bool ExternalImageSibling::isTextureable(const gl::Context *context) const
220 {
221 return mImplementation->isTexturable(context);
222 }
223
isYUV() const224 bool ExternalImageSibling::isYUV() const
225 {
226 return mImplementation->isYUV();
227 }
228
hasFrontBufferUsage() const229 bool ExternalImageSibling::hasFrontBufferUsage() const
230 {
231 return mImplementation->hasFrontBufferUsage();
232 }
233
isCubeMap() const234 bool ExternalImageSibling::isCubeMap() const
235 {
236 return mImplementation->isCubeMap();
237 }
238
hasProtectedContent() const239 bool ExternalImageSibling::hasProtectedContent() const
240 {
241 return mImplementation->hasProtectedContent();
242 }
243
onAttach(const gl::Context * context,rx::UniqueSerial framebufferSerial)244 void ExternalImageSibling::onAttach(const gl::Context *context, rx::UniqueSerial framebufferSerial)
245 {}
246
onDetach(const gl::Context * context,rx::UniqueSerial framebufferSerial)247 void ExternalImageSibling::onDetach(const gl::Context *context, rx::UniqueSerial framebufferSerial)
248 {}
249
getId() const250 GLuint ExternalImageSibling::getId() const
251 {
252 UNREACHABLE();
253 return 0;
254 }
255
initState(GLenum binding,const gl::ImageIndex & imageIndex) const256 gl::InitState ExternalImageSibling::initState(GLenum binding,
257 const gl::ImageIndex &imageIndex) const
258 {
259 return gl::InitState::Initialized;
260 }
261
setInitState(GLenum binding,const gl::ImageIndex & imageIndex,gl::InitState initState)262 void ExternalImageSibling::setInitState(GLenum binding,
263 const gl::ImageIndex &imageIndex,
264 gl::InitState initState)
265 {}
266
getImplementation() const267 rx::ExternalImageSiblingImpl *ExternalImageSibling::getImplementation() const
268 {
269 return mImplementation.get();
270 }
271
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)272 void ExternalImageSibling::onSubjectStateChange(angle::SubjectIndex index,
273 angle::SubjectMessage message)
274 {
275 onStateChange(message);
276 }
277
getAttachmentImpl() const278 rx::FramebufferAttachmentObjectImpl *ExternalImageSibling::getAttachmentImpl() const
279 {
280 return mImplementation.get();
281 }
282
ImageState(ImageID id,EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)283 ImageState::ImageState(ImageID id,
284 EGLenum target,
285 ImageSibling *buffer,
286 const AttributeMap &attribs)
287 : id(id),
288 label(nullptr),
289 target(target),
290 imageIndex(GetImageIndex(target, attribs)),
291 source(buffer),
292 format(GL_NONE),
293 yuv(false),
294 cubeMap(false),
295 size(),
296 samples(),
297 levelCount(1),
298 colorspace(
299 static_cast<EGLenum>(attribs.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_DEFAULT_EXT))),
300 hasProtectedContent(static_cast<bool>(attribs.get(EGL_PROTECTED_CONTENT_EXT, EGL_FALSE)))
301 {}
302
~ImageState()303 ImageState::~ImageState() {}
304
Image(rx::EGLImplFactory * factory,ImageID id,const gl::Context * context,EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)305 Image::Image(rx::EGLImplFactory *factory,
306 ImageID id,
307 const gl::Context *context,
308 EGLenum target,
309 ImageSibling *buffer,
310 const AttributeMap &attribs)
311 : mState(id, target, buffer, attribs),
312 mImplementation(factory->createImage(mState, context, target, attribs)),
313 mOrphanedAndNeedsInit(false),
314 mContextMutex(nullptr)
315 {
316 ASSERT(mImplementation != nullptr);
317 ASSERT(buffer != nullptr);
318
319 if (kIsContextMutexEnabled)
320 {
321 if (context != nullptr)
322 {
323 mContextMutex = context->getContextMutex().getRoot();
324 ASSERT(mContextMutex->isReferenced());
325 }
326 else
327 {
328 mContextMutex = new ContextMutex();
329 }
330 mContextMutex->addRef();
331 }
332
333 mState.source->addImageSource(this);
334 }
335
onDestroy(const Display * display)336 void Image::onDestroy(const Display *display)
337 {
338 // All targets should hold a ref to the egl image and it should not be deleted until there are
339 // no siblings left.
340 ASSERT([&] {
341 std::unique_lock lock(mState.targetsLock);
342 return mState.targets.empty();
343 }());
344
345 // Make sure the implementation gets a chance to clean up before we delete the source.
346 mImplementation->onDestroy(display);
347
348 // Tell the source that it is no longer used by this image
349 if (mState.source != nullptr)
350 {
351 mState.source->removeImageSource(this);
352
353 // If the source is an external object, delete it
354 if (IsExternalImageTarget(mState.target))
355 {
356 ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
357 externalSibling->onDestroy(display);
358 delete externalSibling;
359 }
360
361 mState.source = nullptr;
362 }
363 }
364
~Image()365 Image::~Image()
366 {
367 SafeDelete(mImplementation);
368
369 if (mContextMutex != nullptr)
370 {
371 mContextMutex->release();
372 mContextMutex = nullptr;
373 }
374 }
375
setLabel(EGLLabelKHR label)376 void Image::setLabel(EGLLabelKHR label)
377 {
378 mState.label = label;
379 }
380
getLabel() const381 EGLLabelKHR Image::getLabel() const
382 {
383 return mState.label;
384 }
385
addTargetSibling(ImageSibling * sibling)386 void Image::addTargetSibling(ImageSibling *sibling)
387 {
388 std::unique_lock lock(mState.targetsLock);
389 mState.targets.insert(sibling);
390 }
391
orphanSibling(const gl::Context * context,ImageSibling * sibling)392 angle::Result Image::orphanSibling(const gl::Context *context, ImageSibling *sibling)
393 {
394 ASSERT(sibling != nullptr);
395
396 // notify impl
397 ANGLE_TRY(mImplementation->orphan(context, sibling));
398
399 if (mState.source == sibling)
400 {
401 // The external source of an image cannot be redefined so it cannot be orphaned.
402 ASSERT(!IsExternalImageTarget(mState.target));
403
404 // If the sibling is the source, it cannot be a target.
405 ASSERT([&] {
406 std::unique_lock lock(mState.targetsLock);
407 return mState.targets.find(sibling) == mState.targets.end();
408 }());
409 mState.source = nullptr;
410 mOrphanedAndNeedsInit =
411 (sibling->initState(GL_NONE, mState.imageIndex) == gl::InitState::MayNeedInit);
412 }
413 else
414 {
415 std::unique_lock lock(mState.targetsLock);
416 mState.targets.erase(sibling);
417 }
418
419 return angle::Result::Continue;
420 }
421
getFormat() const422 const gl::Format &Image::getFormat() const
423 {
424 return mState.format;
425 }
426
isRenderable(const gl::Context * context) const427 bool Image::isRenderable(const gl::Context *context) const
428 {
429 return mIsRenderable;
430 }
431
isTexturable(const gl::Context * context) const432 bool Image::isTexturable(const gl::Context *context) const
433 {
434 return mIsTexturable;
435 }
436
isYUV() const437 bool Image::isYUV() const
438 {
439 return mState.yuv;
440 }
441
isExternalImageWithoutIndividualSync() const442 bool Image::isExternalImageWithoutIndividualSync() const
443 {
444 // Only Vulkan images are individually synced.
445 return IsExternalImageTarget(mState.target) && mState.target != EGL_VULKAN_IMAGE_ANGLE;
446 }
447
hasFrontBufferUsage() const448 bool Image::hasFrontBufferUsage() const
449 {
450 if (IsExternalImageTarget(mState.target))
451 {
452 ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
453 return externalSibling->hasFrontBufferUsage();
454 }
455
456 return false;
457 }
458
isCubeMap() const459 bool Image::isCubeMap() const
460 {
461 return mState.cubeMap;
462 }
463
getWidth() const464 size_t Image::getWidth() const
465 {
466 return mState.size.width;
467 }
468
getHeight() const469 size_t Image::getHeight() const
470 {
471 return mState.size.height;
472 }
473
getExtents() const474 const gl::Extents &Image::getExtents() const
475 {
476 return mState.size;
477 }
478
isLayered() const479 bool Image::isLayered() const
480 {
481 return mState.imageIndex.isLayered();
482 }
483
getSamples() const484 size_t Image::getSamples() const
485 {
486 return mState.samples;
487 }
488
getLevelCount() const489 GLuint Image::getLevelCount() const
490 {
491 return mState.levelCount;
492 }
493
hasProtectedContent() const494 bool Image::hasProtectedContent() const
495 {
496 return mState.hasProtectedContent;
497 }
498
isFixedRatedCompression(const gl::Context * context) const499 bool Image::isFixedRatedCompression(const gl::Context *context) const
500 {
501 return mImplementation->isFixedRatedCompression(context);
502 }
503
getImplementation() const504 rx::ImageImpl *Image::getImplementation() const
505 {
506 return mImplementation;
507 }
508
initialize(const Display * display,const gl::Context * context)509 Error Image::initialize(const Display *display, const gl::Context *context)
510 {
511 if (IsExternalImageTarget(mState.target))
512 {
513 ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
514 ANGLE_TRY(externalSibling->initialize(display, context));
515
516 mState.hasProtectedContent = externalSibling->hasProtectedContent();
517 mState.levelCount = externalSibling->getLevelCount();
518 mState.cubeMap = externalSibling->isCubeMap();
519
520 // External siblings can be YUV
521 mState.yuv = externalSibling->isYUV();
522 }
523
524 mState.format = mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex);
525
526 if (mState.colorspace != EGL_GL_COLORSPACE_DEFAULT_EXT)
527 {
528 GLenum nonLinearFormat = mState.format.info->sizedInternalFormat;
529 if (!gl::ColorspaceFormatOverride(mState.colorspace, &nonLinearFormat))
530 {
531 // the colorspace format is not supported
532 return egl::EglBadMatch();
533 }
534 mState.format = gl::Format(nonLinearFormat);
535 }
536
537 if (!IsExternalImageTarget(mState.target))
538 {
539 // Account for the fact that GL_ANGLE_yuv_internal_format extension maybe enabled,
540 // in which case the internal format itself could be YUV.
541 mState.yuv = gl::IsYuvFormat(mState.format.info->sizedInternalFormat);
542 }
543
544 mState.size = mState.source->getAttachmentSize(mState.imageIndex);
545 mState.samples = mState.source->getAttachmentSamples(mState.imageIndex);
546
547 if (IsTextureTarget(mState.target))
548 {
549 mState.size.depth = 1;
550 }
551
552 Error error = mImplementation->initialize(display);
553 if (error.isError())
554 {
555 return error;
556 }
557
558 if (IsTextureTarget(mState.target))
559 {
560 mIsTexturable = true;
561 mIsRenderable = mState.format.info->textureAttachmentSupport(context->getClientVersion(),
562 context->getExtensions());
563 }
564 else if (IsRenderbufferTarget(mState.target))
565 {
566 mIsTexturable = true;
567 mIsRenderable = mState.format.info->renderbufferSupport(context->getClientVersion(),
568 context->getExtensions());
569 }
570 else if (IsExternalImageTarget(mState.target))
571 {
572 ASSERT(mState.source != nullptr);
573 mIsTexturable = rx::GetAs<ExternalImageSibling>(mState.source)->isTextureable(context);
574 mIsRenderable = rx::GetAs<ExternalImageSibling>(mState.source)
575 ->isRenderable(context, GL_NONE, gl::ImageIndex());
576 }
577 else
578 {
579 UNREACHABLE();
580 }
581
582 return NoError();
583 }
584
orphaned() const585 bool Image::orphaned() const
586 {
587 return (mState.source == nullptr);
588 }
589
sourceInitState() const590 gl::InitState Image::sourceInitState() const
591 {
592 if (orphaned())
593 {
594 return mOrphanedAndNeedsInit ? gl::InitState::MayNeedInit : gl::InitState::Initialized;
595 }
596
597 return mState.source->initState(GL_NONE, mState.imageIndex);
598 }
599
setInitState(gl::InitState initState)600 void Image::setInitState(gl::InitState initState)
601 {
602 if (orphaned())
603 {
604 mOrphanedAndNeedsInit = false;
605 }
606
607 return mState.source->setInitState(GL_NONE, mState.imageIndex, initState);
608 }
609
exportVkImage(void * vkImage,void * vkImageCreateInfo)610 Error Image::exportVkImage(void *vkImage, void *vkImageCreateInfo)
611 {
612 return mImplementation->exportVkImage(vkImage, vkImageCreateInfo);
613 }
614
notifySiblings(const ImageSibling * notifier,angle::SubjectMessage message)615 void Image::notifySiblings(const ImageSibling *notifier, angle::SubjectMessage message)
616 {
617 if (mState.source && mState.source != notifier)
618 {
619 mState.source->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
620 }
621
622 std::unique_lock lock(mState.targetsLock);
623 for (ImageSibling *target : mState.targets)
624 {
625 if (target != notifier)
626 {
627 target->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
628 }
629 }
630 }
631
632 } // namespace egl
633