diff options
Diffstat (limited to '')
-rw-r--r-- | gfx/angle/checkout/src/libANGLE/Image.cpp | 581 |
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 |