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
getImplementation() const499 rx::ImageImpl *Image::getImplementation() const
500 {
501 return mImplementation;
502 }
503
initialize(const Display * display,const gl::Context * context)504 Error Image::initialize(const Display *display, const gl::Context *context)
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