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