Edit

kc3-lang/angle/src/libANGLE/Image.cpp

Branch :

  • Show log

    Commit

  • Author : Jeff Vigil
    Date : 2021-03-25 15:43:06
    Hash : 6136620b
    Message : Reland "EGL: GLES: Implement GL_EXT_protected_textures" This is a reland of 6210a9b34a721df2c84cf69170ad9bf7ba40e4aa This removes changes in gl backend. Original change's description: > EGL: GLES: Implement GL_EXT_protected_textures > > Implement EGL_EXT_protected_content Images > Add protected member to Images and Textures > Add error when creating objects if not supported or > does't match native buffer > When creating siblings pass protected state > Add extension caps > Add Validation > Add GetTexParameter and SetTextparameter > Add protected to Texture and state > Expand tests for images and textures > > Test: angle_end2end_test --gtest_filter=EGLProtectedContentTest > > Bug: angleproject:3965 > Change-Id: I35a89b4e80bba6d9b6831c68e71630eef304dacb > Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2802852 > Commit-Queue: Mohan Maiya <m.maiya@samsung.com> > Reviewed-by: Geoff Lang <geofflang@chromium.org> > Reviewed-by: Jamie Madill <jmadill@chromium.org> > Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Test: angle_end2end_test --gtest_filter=EGLProtectedContentTest Bug: angleproject:3965 Change-Id: Id36d697c53afc0f0dadf92bda4565f9157f4fc2a Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3076825 Commit-Queue: Brandon Schade <b.schade@samsung.com> Reviewed-by: Ian Elliott <ianelliott@google.com> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/libANGLE/Image.cpp
  • //
    // 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)
    {
        if (mTargetOf.get() != nullptr)
        {
            // Can't be a target and have sources.
            ASSERT(mSourcesOf.empty());
    
            ANGLE_TRY(mTargetOf->orphanSibling(context, this));
            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::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());
    }
    
    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::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(const gl::ImageIndex &imageIndex) const
    {
        return gl::InitState::Initialized;
    }
    
    void ExternalImageSibling::setInitState(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),
          targets(),
          format(GL_NONE),
          yuv(false),
          size(),
          samples(),
          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(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)
    {
        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 orpahend.
            ASSERT(!IsExternalImageTarget(mState.sourceType));
    
            // If the sibling is the source, it cannot be a target.
            ASSERT(mState.targets.find(sibling) == mState.targets.end());
            mState.source = nullptr;
            mOrphanedAndNeedsInit =
                (sibling->initState(mState.imageIndex) == gl::InitState::MayNeedInit);
        }
        else
        {
            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;
    }
    
    size_t Image::getWidth() const
    {
        return mState.size.width;
    }
    
    size_t Image::getHeight() const
    {
        return mState.size.height;
    }
    
    bool Image::isLayered() const
    {
        return mState.imageIndex.isLayered();
    }
    
    size_t Image::getSamples() const
    {
        return mState.samples;
    }
    
    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();
    
            // Only 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);
        }
    
        mState.size    = mState.source->getAttachmentSize(mState.imageIndex);
        mState.samples = mState.source->getAttachmentSamples(mState.imageIndex);
    
        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(mState.imageIndex);
    }
    
    void Image::setInitState(gl::InitState initState)
    {
        if (orphaned())
        {
            mOrphanedAndNeedsInit = false;
        }
    
        return mState.source->setInitState(mState.imageIndex, initState);
    }
    
    void Image::notifySiblings(const ImageSibling *notifier, angle::SubjectMessage message)
    {
        if (mState.source && mState.source != notifier)
        {
            mState.source->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
        }
    
        for (ImageSibling *target : mState.targets)
        {
            if (target != notifier)
            {
                target->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
            }
        }
    }
    
    }  // namespace egl