summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/libANGLE/Image.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/Image.cpp')
-rw-r--r--gfx/angle/checkout/src/libANGLE/Image.cpp581
1 files changed, 581 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/Image.cpp b/gfx/angle/checkout/src/libANGLE/Image.cpp
new file mode 100644
index 0000000000..6292b5ee46
--- /dev/null
+++ b/gfx/angle/checkout/src/libANGLE/Image.cpp
@@ -0,0 +1,581 @@
+//
+// Copyright 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Image.cpp: Implements the egl::Image class representing the EGLimage object.
+
+#include "libANGLE/Image.h"
+
+#include "common/debug.h"
+#include "common/utilities.h"
+#include "libANGLE/Context.h"
+#include "libANGLE/Renderbuffer.h"
+#include "libANGLE/Texture.h"
+#include "libANGLE/angletypes.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/EGLImplFactory.h"
+#include "libANGLE/renderer/ImageImpl.h"
+
+namespace egl
+{
+
+namespace
+{
+gl::ImageIndex GetImageIndex(EGLenum eglTarget, const egl::AttributeMap &attribs)
+{
+ if (!IsTextureTarget(eglTarget))
+ {
+ return gl::ImageIndex();
+ }
+
+ gl::TextureTarget target = egl_gl::EGLImageTargetToTextureTarget(eglTarget);
+ GLint mip = static_cast<GLint>(attribs.get(EGL_GL_TEXTURE_LEVEL_KHR, 0));
+ GLint layer = static_cast<GLint>(attribs.get(EGL_GL_TEXTURE_ZOFFSET_KHR, 0));
+
+ if (target == gl::TextureTarget::_3D)
+ {
+ return gl::ImageIndex::Make3D(mip, layer);
+ }
+ else
+ {
+ ASSERT(layer == 0);
+ return gl::ImageIndex::MakeFromTarget(target, mip, 1);
+ }
+}
+
+const Display *DisplayFromContext(const gl::Context *context)
+{
+ return (context ? context->getDisplay() : nullptr);
+}
+
+angle::SubjectIndex kExternalImageImplSubjectIndex = 0;
+} // anonymous namespace
+
+ImageSibling::ImageSibling() : FramebufferAttachmentObject(), mSourcesOf(), mTargetOf() {}
+
+ImageSibling::~ImageSibling()
+{
+ // EGL images should hold a ref to their targets and siblings, a Texture should not be deletable
+ // while it is attached to an EGL image.
+ // Child class should orphan images before destruction.
+ ASSERT(mSourcesOf.empty());
+ ASSERT(mTargetOf.get() == nullptr);
+}
+
+void ImageSibling::setTargetImage(const gl::Context *context, egl::Image *imageTarget)
+{
+ ASSERT(imageTarget != nullptr);
+ mTargetOf.set(DisplayFromContext(context), imageTarget);
+ imageTarget->addTargetSibling(this);
+}
+
+angle::Result ImageSibling::orphanImages(const gl::Context *context,
+ RefCountObjectReleaser<Image> *outReleaseImage)
+{
+ ASSERT(outReleaseImage != nullptr);
+
+ if (mTargetOf.get() != nullptr)
+ {
+ // Can't be a target and have sources.
+ ASSERT(mSourcesOf.empty());
+
+ ANGLE_TRY(mTargetOf->orphanSibling(context, this));
+ *outReleaseImage = mTargetOf.set(DisplayFromContext(context), nullptr);
+ }
+ else
+ {
+ for (Image *sourceImage : mSourcesOf)
+ {
+ ANGLE_TRY(sourceImage->orphanSibling(context, this));
+ }
+ mSourcesOf.clear();
+ }
+
+ return angle::Result::Continue;
+}
+
+void ImageSibling::addImageSource(egl::Image *imageSource)
+{
+ ASSERT(imageSource != nullptr);
+ mSourcesOf.insert(imageSource);
+}
+
+void ImageSibling::removeImageSource(egl::Image *imageSource)
+{
+ ASSERT(mSourcesOf.find(imageSource) != mSourcesOf.end());
+ mSourcesOf.erase(imageSource);
+}
+
+bool ImageSibling::isEGLImageTarget() const
+{
+ return (mTargetOf.get() != nullptr);
+}
+
+gl::InitState ImageSibling::sourceEGLImageInitState() const
+{
+ ASSERT(isEGLImageTarget());
+ return mTargetOf->sourceInitState();
+}
+
+void ImageSibling::setSourceEGLImageInitState(gl::InitState initState) const
+{
+ ASSERT(isEGLImageTarget());
+ mTargetOf->setInitState(initState);
+}
+
+bool ImageSibling::isRenderable(const gl::Context *context,
+ GLenum binding,
+ const gl::ImageIndex &imageIndex) const
+{
+ ASSERT(isEGLImageTarget());
+ return mTargetOf->isRenderable(context);
+}
+
+bool ImageSibling::isYUV() const
+{
+ return mTargetOf.get() && mTargetOf->isYUV();
+}
+
+bool ImageSibling::isCreatedWithAHB() const
+{
+ return mTargetOf.get() && mTargetOf->isCreatedWithAHB();
+}
+
+bool ImageSibling::hasProtectedContent() const
+{
+ return mTargetOf.get() && mTargetOf->hasProtectedContent();
+}
+
+void ImageSibling::notifySiblings(angle::SubjectMessage message)
+{
+ if (mTargetOf.get())
+ {
+ mTargetOf->notifySiblings(this, message);
+ }
+ for (Image *source : mSourcesOf)
+ {
+ source->notifySiblings(this, message);
+ }
+}
+
+ExternalImageSibling::ExternalImageSibling(rx::EGLImplFactory *factory,
+ const gl::Context *context,
+ EGLenum target,
+ EGLClientBuffer buffer,
+ const AttributeMap &attribs)
+ : mImplementation(factory->createExternalImageSibling(context, target, buffer, attribs)),
+ mImplObserverBinding(this, kExternalImageImplSubjectIndex)
+{
+ mImplObserverBinding.bind(mImplementation.get());
+}
+
+ExternalImageSibling::~ExternalImageSibling() = default;
+
+void ExternalImageSibling::onDestroy(const egl::Display *display)
+{
+ mImplementation->onDestroy(display);
+}
+
+Error ExternalImageSibling::initialize(const egl::Display *display)
+{
+ return mImplementation->initialize(display);
+}
+
+gl::Extents ExternalImageSibling::getAttachmentSize(const gl::ImageIndex &imageIndex) const
+{
+ return mImplementation->getSize();
+}
+
+gl::Format ExternalImageSibling::getAttachmentFormat(GLenum binding,
+ const gl::ImageIndex &imageIndex) const
+{
+ return mImplementation->getFormat();
+}
+
+GLsizei ExternalImageSibling::getAttachmentSamples(const gl::ImageIndex &imageIndex) const
+{
+ return static_cast<GLsizei>(mImplementation->getSamples());
+}
+
+GLuint ExternalImageSibling::getLevelCount() const
+{
+ return static_cast<GLuint>(mImplementation->getLevelCount());
+}
+
+bool ExternalImageSibling::isRenderable(const gl::Context *context,
+ GLenum binding,
+ const gl::ImageIndex &imageIndex) const
+{
+ return mImplementation->isRenderable(context);
+}
+
+bool ExternalImageSibling::isTextureable(const gl::Context *context) const
+{
+ return mImplementation->isTexturable(context);
+}
+
+bool ExternalImageSibling::isYUV() const
+{
+ return mImplementation->isYUV();
+}
+
+bool ExternalImageSibling::isCubeMap() const
+{
+ return mImplementation->isCubeMap();
+}
+
+bool ExternalImageSibling::hasProtectedContent() const
+{
+ return mImplementation->hasProtectedContent();
+}
+
+void ExternalImageSibling::onAttach(const gl::Context *context, rx::Serial framebufferSerial) {}
+
+void ExternalImageSibling::onDetach(const gl::Context *context, rx::Serial framebufferSerial) {}
+
+GLuint ExternalImageSibling::getId() const
+{
+ UNREACHABLE();
+ return 0;
+}
+
+gl::InitState ExternalImageSibling::initState(GLenum binding,
+ const gl::ImageIndex &imageIndex) const
+{
+ return gl::InitState::Initialized;
+}
+
+void ExternalImageSibling::setInitState(GLenum binding,
+ const gl::ImageIndex &imageIndex,
+ gl::InitState initState)
+{}
+
+rx::ExternalImageSiblingImpl *ExternalImageSibling::getImplementation() const
+{
+ return mImplementation.get();
+}
+
+void ExternalImageSibling::onSubjectStateChange(angle::SubjectIndex index,
+ angle::SubjectMessage message)
+{
+ onStateChange(message);
+}
+
+rx::FramebufferAttachmentObjectImpl *ExternalImageSibling::getAttachmentImpl() const
+{
+ return mImplementation.get();
+}
+
+ImageState::ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs)
+ : label(nullptr),
+ target(target),
+ imageIndex(GetImageIndex(target, attribs)),
+ source(buffer),
+ format(GL_NONE),
+ yuv(false),
+ cubeMap(false),
+ size(),
+ samples(),
+ levelCount(1),
+ sourceType(target),
+ colorspace(
+ static_cast<EGLenum>(attribs.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_DEFAULT_EXT))),
+ hasProtectedContent(static_cast<bool>(attribs.get(EGL_PROTECTED_CONTENT_EXT, EGL_FALSE)))
+{}
+
+ImageState::~ImageState() {}
+
+Image::Image(rx::EGLImplFactory *factory,
+ const gl::Context *context,
+ EGLenum target,
+ ImageSibling *buffer,
+ const AttributeMap &attribs)
+ : mState(target, buffer, attribs),
+ mImplementation(factory->createImage(mState, context, target, attribs)),
+ mOrphanedAndNeedsInit(false)
+{
+ ASSERT(mImplementation != nullptr);
+ ASSERT(buffer != nullptr);
+
+ mState.source->addImageSource(this);
+}
+
+void Image::onDestroy(const Display *display)
+{
+ // All targets should hold a ref to the egl image and it should not be deleted until there are
+ // no siblings left.
+ ASSERT([&] {
+ std::unique_lock lock(mState.targetsLock);
+ return mState.targets.empty();
+ }());
+
+ // Make sure the implementation gets a chance to clean up before we delete the source.
+ mImplementation->onDestroy(display);
+
+ // Tell the source that it is no longer used by this image
+ if (mState.source != nullptr)
+ {
+ mState.source->removeImageSource(this);
+
+ // If the source is an external object, delete it
+ if (IsExternalImageTarget(mState.sourceType))
+ {
+ ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
+ externalSibling->onDestroy(display);
+ delete externalSibling;
+ }
+
+ mState.source = nullptr;
+ }
+}
+
+Image::~Image()
+{
+ SafeDelete(mImplementation);
+}
+
+void Image::setLabel(EGLLabelKHR label)
+{
+ mState.label = label;
+}
+
+EGLLabelKHR Image::getLabel() const
+{
+ return mState.label;
+}
+
+void Image::addTargetSibling(ImageSibling *sibling)
+{
+ std::unique_lock lock(mState.targetsLock);
+ mState.targets.insert(sibling);
+}
+
+angle::Result Image::orphanSibling(const gl::Context *context, ImageSibling *sibling)
+{
+ ASSERT(sibling != nullptr);
+
+ // notify impl
+ ANGLE_TRY(mImplementation->orphan(context, sibling));
+
+ if (mState.source == sibling)
+ {
+ // The external source of an image cannot be redefined so it cannot be orphaned.
+ ASSERT(!IsExternalImageTarget(mState.sourceType));
+
+ // If the sibling is the source, it cannot be a target.
+ ASSERT([&] {
+ std::unique_lock lock(mState.targetsLock);
+ return mState.targets.find(sibling) == mState.targets.end();
+ }());
+ mState.source = nullptr;
+ mOrphanedAndNeedsInit =
+ (sibling->initState(GL_NONE, mState.imageIndex) == gl::InitState::MayNeedInit);
+ }
+ else
+ {
+ std::unique_lock lock(mState.targetsLock);
+ mState.targets.erase(sibling);
+ }
+
+ return angle::Result::Continue;
+}
+
+const gl::Format &Image::getFormat() const
+{
+ return mState.format;
+}
+
+bool Image::isRenderable(const gl::Context *context) const
+{
+ if (IsTextureTarget(mState.sourceType))
+ {
+ return mState.format.info->textureAttachmentSupport(context->getClientVersion(),
+ context->getExtensions());
+ }
+ else if (IsRenderbufferTarget(mState.sourceType))
+ {
+ return mState.format.info->renderbufferSupport(context->getClientVersion(),
+ context->getExtensions());
+ }
+ else if (IsExternalImageTarget(mState.sourceType))
+ {
+ ASSERT(mState.source != nullptr);
+ return mState.source->isRenderable(context, GL_NONE, gl::ImageIndex());
+ }
+
+ UNREACHABLE();
+ return false;
+}
+
+bool Image::isTexturable(const gl::Context *context) const
+{
+ if (IsTextureTarget(mState.sourceType))
+ {
+ return mState.format.info->textureSupport(context->getClientVersion(),
+ context->getExtensions());
+ }
+ else if (IsRenderbufferTarget(mState.sourceType))
+ {
+ return true;
+ }
+ else if (IsExternalImageTarget(mState.sourceType))
+ {
+ ASSERT(mState.source != nullptr);
+ return rx::GetAs<ExternalImageSibling>(mState.source)->isTextureable(context);
+ }
+
+ UNREACHABLE();
+ return false;
+}
+
+bool Image::isYUV() const
+{
+ return mState.yuv;
+}
+
+bool Image::isCreatedWithAHB() const
+{
+ return mState.target == EGL_NATIVE_BUFFER_ANDROID;
+}
+
+bool Image::isCubeMap() const
+{
+ return mState.cubeMap;
+}
+
+size_t Image::getWidth() const
+{
+ return mState.size.width;
+}
+
+size_t Image::getHeight() const
+{
+ return mState.size.height;
+}
+
+const gl::Extents &Image::getExtents() const
+{
+ return mState.size;
+}
+
+bool Image::isLayered() const
+{
+ return mState.imageIndex.isLayered();
+}
+
+size_t Image::getSamples() const
+{
+ return mState.samples;
+}
+
+GLuint Image::getLevelCount() const
+{
+ return mState.levelCount;
+}
+
+bool Image::hasProtectedContent() const
+{
+ return mState.hasProtectedContent;
+}
+
+rx::ImageImpl *Image::getImplementation() const
+{
+ return mImplementation;
+}
+
+Error Image::initialize(const Display *display)
+{
+ if (IsExternalImageTarget(mState.sourceType))
+ {
+ ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
+ ANGLE_TRY(externalSibling->initialize(display));
+
+ mState.hasProtectedContent = externalSibling->hasProtectedContent();
+ mState.levelCount = externalSibling->getLevelCount();
+ mState.cubeMap = externalSibling->isCubeMap();
+
+ // External siblings can be YUV
+ mState.yuv = externalSibling->isYUV();
+ }
+
+ mState.format = mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex);
+
+ if (mState.colorspace != EGL_GL_COLORSPACE_DEFAULT_EXT)
+ {
+ GLenum nonLinearFormat = mState.format.info->sizedInternalFormat;
+ if (!gl::ColorspaceFormatOverride(mState.colorspace, &nonLinearFormat))
+ {
+ // the colorspace format is not supported
+ return egl::EglBadMatch();
+ }
+ mState.format = gl::Format(nonLinearFormat);
+ }
+
+ if (!IsExternalImageTarget(mState.sourceType))
+ {
+ // Account for the fact that GL_ANGLE_yuv_internal_format extension maybe enabled,
+ // in which case the internal format itself could be YUV.
+ mState.yuv = gl::IsYuvFormat(mState.format.info->sizedInternalFormat);
+ }
+
+ mState.size = mState.source->getAttachmentSize(mState.imageIndex);
+ mState.samples = mState.source->getAttachmentSamples(mState.imageIndex);
+
+ if (IsTextureTarget(mState.sourceType))
+ {
+ mState.size.depth = 1;
+ }
+
+ return mImplementation->initialize(display);
+}
+
+bool Image::orphaned() const
+{
+ return (mState.source == nullptr);
+}
+
+gl::InitState Image::sourceInitState() const
+{
+ if (orphaned())
+ {
+ return mOrphanedAndNeedsInit ? gl::InitState::MayNeedInit : gl::InitState::Initialized;
+ }
+
+ return mState.source->initState(GL_NONE, mState.imageIndex);
+}
+
+void Image::setInitState(gl::InitState initState)
+{
+ if (orphaned())
+ {
+ mOrphanedAndNeedsInit = false;
+ }
+
+ return mState.source->setInitState(GL_NONE, mState.imageIndex, initState);
+}
+
+Error Image::exportVkImage(void *vkImage, void *vkImageCreateInfo)
+{
+ return mImplementation->exportVkImage(vkImage, vkImageCreateInfo);
+}
+
+void Image::notifySiblings(const ImageSibling *notifier, angle::SubjectMessage message)
+{
+ if (mState.source && mState.source != notifier)
+ {
+ mState.source->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
+ }
+
+ std::unique_lock lock(mState.targetsLock);
+ for (ImageSibling *target : mState.targets)
+ {
+ if (target != notifier)
+ {
+ target->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
+ }
+ }
+}
+
+} // namespace egl