tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Image.cpp (15869B)


      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 {
     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 
     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 
     56 ImageSibling::ImageSibling() : FramebufferAttachmentObject(), mSourcesOf(), mTargetOf() {}
     57 
     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 
     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 
     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 
     99 void ImageSibling::addImageSource(egl::Image *imageSource)
    100 {
    101    ASSERT(imageSource != nullptr);
    102    mSourcesOf.insert(imageSource);
    103 }
    104 
    105 void ImageSibling::removeImageSource(egl::Image *imageSource)
    106 {
    107    ASSERT(mSourcesOf.find(imageSource) != mSourcesOf.end());
    108    mSourcesOf.erase(imageSource);
    109 }
    110 
    111 bool ImageSibling::isEGLImageTarget() const
    112 {
    113    return (mTargetOf.get() != nullptr);
    114 }
    115 
    116 gl::InitState ImageSibling::sourceEGLImageInitState() const
    117 {
    118    ASSERT(isEGLImageTarget());
    119    return mTargetOf->sourceInitState();
    120 }
    121 
    122 void ImageSibling::setSourceEGLImageInitState(gl::InitState initState) const
    123 {
    124    ASSERT(isEGLImageTarget());
    125    mTargetOf->setInitState(initState);
    126 }
    127 
    128 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 
    136 bool ImageSibling::isYUV() const
    137 {
    138    return mTargetOf.get() && mTargetOf->isYUV();
    139 }
    140 
    141 bool ImageSibling::isCreatedWithAHB() const
    142 {
    143    return mTargetOf.get() && mTargetOf->isCreatedWithAHB();
    144 }
    145 
    146 bool ImageSibling::hasProtectedContent() const
    147 {
    148    return mTargetOf.get() && mTargetOf->hasProtectedContent();
    149 }
    150 
    151 void ImageSibling::notifySiblings(angle::SubjectMessage message)
    152 {
    153    if (mTargetOf.get())
    154    {
    155        mTargetOf->notifySiblings(this, message);
    156    }
    157    for (Image *source : mSourcesOf)
    158    {
    159        source->notifySiblings(this, message);
    160    }
    161 }
    162 
    163 ExternalImageSibling::ExternalImageSibling(rx::EGLImplFactory *factory,
    164                                           const gl::Context *context,
    165                                           EGLenum target,
    166                                           EGLClientBuffer buffer,
    167                                           const AttributeMap &attribs)
    168    : mImplementation(factory->createExternalImageSibling(context, target, buffer, attribs)),
    169      mImplObserverBinding(this, kExternalImageImplSubjectIndex)
    170 {
    171    mImplObserverBinding.bind(mImplementation.get());
    172 }
    173 
    174 ExternalImageSibling::~ExternalImageSibling() = default;
    175 
    176 void ExternalImageSibling::onDestroy(const egl::Display *display)
    177 {
    178    mImplementation->onDestroy(display);
    179 }
    180 
    181 Error ExternalImageSibling::initialize(const egl::Display *display)
    182 {
    183    return mImplementation->initialize(display);
    184 }
    185 
    186 gl::Extents ExternalImageSibling::getAttachmentSize(const gl::ImageIndex &imageIndex) const
    187 {
    188    return mImplementation->getSize();
    189 }
    190 
    191 gl::Format ExternalImageSibling::getAttachmentFormat(GLenum binding,
    192                                                     const gl::ImageIndex &imageIndex) const
    193 {
    194    return mImplementation->getFormat();
    195 }
    196 
    197 GLsizei ExternalImageSibling::getAttachmentSamples(const gl::ImageIndex &imageIndex) const
    198 {
    199    return static_cast<GLsizei>(mImplementation->getSamples());
    200 }
    201 
    202 GLuint ExternalImageSibling::getLevelCount() const
    203 {
    204    return static_cast<GLuint>(mImplementation->getLevelCount());
    205 }
    206 
    207 bool ExternalImageSibling::isRenderable(const gl::Context *context,
    208                                        GLenum binding,
    209                                        const gl::ImageIndex &imageIndex) const
    210 {
    211    return mImplementation->isRenderable(context);
    212 }
    213 
    214 bool ExternalImageSibling::isTextureable(const gl::Context *context) const
    215 {
    216    return mImplementation->isTexturable(context);
    217 }
    218 
    219 bool ExternalImageSibling::isYUV() const
    220 {
    221    return mImplementation->isYUV();
    222 }
    223 
    224 bool ExternalImageSibling::isCubeMap() const
    225 {
    226    return mImplementation->isCubeMap();
    227 }
    228 
    229 bool ExternalImageSibling::hasProtectedContent() const
    230 {
    231    return mImplementation->hasProtectedContent();
    232 }
    233 
    234 void ExternalImageSibling::onAttach(const gl::Context *context, rx::Serial framebufferSerial) {}
    235 
    236 void ExternalImageSibling::onDetach(const gl::Context *context, rx::Serial framebufferSerial) {}
    237 
    238 GLuint ExternalImageSibling::getId() const
    239 {
    240    UNREACHABLE();
    241    return 0;
    242 }
    243 
    244 gl::InitState ExternalImageSibling::initState(GLenum binding,
    245                                              const gl::ImageIndex &imageIndex) const
    246 {
    247    return gl::InitState::Initialized;
    248 }
    249 
    250 void ExternalImageSibling::setInitState(GLenum binding,
    251                                        const gl::ImageIndex &imageIndex,
    252                                        gl::InitState initState)
    253 {}
    254 
    255 rx::ExternalImageSiblingImpl *ExternalImageSibling::getImplementation() const
    256 {
    257    return mImplementation.get();
    258 }
    259 
    260 void ExternalImageSibling::onSubjectStateChange(angle::SubjectIndex index,
    261                                                angle::SubjectMessage message)
    262 {
    263    onStateChange(message);
    264 }
    265 
    266 rx::FramebufferAttachmentObjectImpl *ExternalImageSibling::getAttachmentImpl() const
    267 {
    268    return mImplementation.get();
    269 }
    270 
    271 ImageState::ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs)
    272    : label(nullptr),
    273      target(target),
    274      imageIndex(GetImageIndex(target, attribs)),
    275      source(buffer),
    276      format(GL_NONE),
    277      yuv(false),
    278      cubeMap(false),
    279      size(),
    280      samples(),
    281      levelCount(1),
    282      sourceType(target),
    283      colorspace(
    284          static_cast<EGLenum>(attribs.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_DEFAULT_EXT))),
    285      hasProtectedContent(static_cast<bool>(attribs.get(EGL_PROTECTED_CONTENT_EXT, EGL_FALSE)))
    286 {}
    287 
    288 ImageState::~ImageState() {}
    289 
    290 Image::Image(rx::EGLImplFactory *factory,
    291             const gl::Context *context,
    292             EGLenum target,
    293             ImageSibling *buffer,
    294             const AttributeMap &attribs)
    295    : mState(target, buffer, attribs),
    296      mImplementation(factory->createImage(mState, context, target, attribs)),
    297      mOrphanedAndNeedsInit(false)
    298 {
    299    ASSERT(mImplementation != nullptr);
    300    ASSERT(buffer != nullptr);
    301 
    302    mState.source->addImageSource(this);
    303 }
    304 
    305 void Image::onDestroy(const Display *display)
    306 {
    307    // All targets should hold a ref to the egl image and it should not be deleted until there are
    308    // no siblings left.
    309    ASSERT([&] {
    310        std::unique_lock lock(mState.targetsLock);
    311        return mState.targets.empty();
    312    }());
    313 
    314    // Make sure the implementation gets a chance to clean up before we delete the source.
    315    mImplementation->onDestroy(display);
    316 
    317    // Tell the source that it is no longer used by this image
    318    if (mState.source != nullptr)
    319    {
    320        mState.source->removeImageSource(this);
    321 
    322        // If the source is an external object, delete it
    323        if (IsExternalImageTarget(mState.sourceType))
    324        {
    325            ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
    326            externalSibling->onDestroy(display);
    327            delete externalSibling;
    328        }
    329 
    330        mState.source = nullptr;
    331    }
    332 }
    333 
    334 Image::~Image()
    335 {
    336    SafeDelete(mImplementation);
    337 }
    338 
    339 void Image::setLabel(EGLLabelKHR label)
    340 {
    341    mState.label = label;
    342 }
    343 
    344 EGLLabelKHR Image::getLabel() const
    345 {
    346    return mState.label;
    347 }
    348 
    349 void Image::addTargetSibling(ImageSibling *sibling)
    350 {
    351    std::unique_lock lock(mState.targetsLock);
    352    mState.targets.insert(sibling);
    353 }
    354 
    355 angle::Result Image::orphanSibling(const gl::Context *context, ImageSibling *sibling)
    356 {
    357    ASSERT(sibling != nullptr);
    358 
    359    // notify impl
    360    ANGLE_TRY(mImplementation->orphan(context, sibling));
    361 
    362    if (mState.source == sibling)
    363    {
    364        // The external source of an image cannot be redefined so it cannot be orphaned.
    365        ASSERT(!IsExternalImageTarget(mState.sourceType));
    366 
    367        // If the sibling is the source, it cannot be a target.
    368        ASSERT([&] {
    369            std::unique_lock lock(mState.targetsLock);
    370            return mState.targets.find(sibling) == mState.targets.end();
    371        }());
    372        mState.source = nullptr;
    373        mOrphanedAndNeedsInit =
    374            (sibling->initState(GL_NONE, mState.imageIndex) == gl::InitState::MayNeedInit);
    375    }
    376    else
    377    {
    378        std::unique_lock lock(mState.targetsLock);
    379        mState.targets.erase(sibling);
    380    }
    381 
    382    return angle::Result::Continue;
    383 }
    384 
    385 const gl::Format &Image::getFormat() const
    386 {
    387    return mState.format;
    388 }
    389 
    390 bool Image::isRenderable(const gl::Context *context) const
    391 {
    392    if (IsTextureTarget(mState.sourceType))
    393    {
    394        return mState.format.info->textureAttachmentSupport(context->getClientVersion(),
    395                                                            context->getExtensions());
    396    }
    397    else if (IsRenderbufferTarget(mState.sourceType))
    398    {
    399        return mState.format.info->renderbufferSupport(context->getClientVersion(),
    400                                                       context->getExtensions());
    401    }
    402    else if (IsExternalImageTarget(mState.sourceType))
    403    {
    404        ASSERT(mState.source != nullptr);
    405        return mState.source->isRenderable(context, GL_NONE, gl::ImageIndex());
    406    }
    407 
    408    UNREACHABLE();
    409    return false;
    410 }
    411 
    412 bool Image::isTexturable(const gl::Context *context) const
    413 {
    414    if (IsTextureTarget(mState.sourceType))
    415    {
    416        return mState.format.info->textureSupport(context->getClientVersion(),
    417                                                  context->getExtensions());
    418    }
    419    else if (IsRenderbufferTarget(mState.sourceType))
    420    {
    421        return true;
    422    }
    423    else if (IsExternalImageTarget(mState.sourceType))
    424    {
    425        ASSERT(mState.source != nullptr);
    426        return rx::GetAs<ExternalImageSibling>(mState.source)->isTextureable(context);
    427    }
    428 
    429    UNREACHABLE();
    430    return false;
    431 }
    432 
    433 bool Image::isYUV() const
    434 {
    435    return mState.yuv;
    436 }
    437 
    438 bool Image::isCreatedWithAHB() const
    439 {
    440    return mState.target == EGL_NATIVE_BUFFER_ANDROID;
    441 }
    442 
    443 bool Image::isCubeMap() const
    444 {
    445    return mState.cubeMap;
    446 }
    447 
    448 size_t Image::getWidth() const
    449 {
    450    return mState.size.width;
    451 }
    452 
    453 size_t Image::getHeight() const
    454 {
    455    return mState.size.height;
    456 }
    457 
    458 const gl::Extents &Image::getExtents() const
    459 {
    460    return mState.size;
    461 }
    462 
    463 bool Image::isLayered() const
    464 {
    465    return mState.imageIndex.isLayered();
    466 }
    467 
    468 size_t Image::getSamples() const
    469 {
    470    return mState.samples;
    471 }
    472 
    473 GLuint Image::getLevelCount() const
    474 {
    475    return mState.levelCount;
    476 }
    477 
    478 bool Image::hasProtectedContent() const
    479 {
    480    return mState.hasProtectedContent;
    481 }
    482 
    483 rx::ImageImpl *Image::getImplementation() const
    484 {
    485    return mImplementation;
    486 }
    487 
    488 Error Image::initialize(const Display *display)
    489 {
    490    if (IsExternalImageTarget(mState.sourceType))
    491    {
    492        ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
    493        ANGLE_TRY(externalSibling->initialize(display));
    494 
    495        mState.hasProtectedContent = externalSibling->hasProtectedContent();
    496        mState.levelCount          = externalSibling->getLevelCount();
    497        mState.cubeMap             = externalSibling->isCubeMap();
    498 
    499        // External siblings can be YUV
    500        mState.yuv = externalSibling->isYUV();
    501    }
    502 
    503    mState.format = mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex);
    504 
    505    if (mState.colorspace != EGL_GL_COLORSPACE_DEFAULT_EXT)
    506    {
    507        GLenum nonLinearFormat = mState.format.info->sizedInternalFormat;
    508        if (!gl::ColorspaceFormatOverride(mState.colorspace, &nonLinearFormat))
    509        {
    510            // the colorspace format is not supported
    511            return egl::EglBadMatch();
    512        }
    513        mState.format = gl::Format(nonLinearFormat);
    514    }
    515 
    516    if (!IsExternalImageTarget(mState.sourceType))
    517    {
    518        // Account for the fact that GL_ANGLE_yuv_internal_format extension maybe enabled,
    519        // in which case the internal format itself could be YUV.
    520        mState.yuv = gl::IsYuvFormat(mState.format.info->sizedInternalFormat);
    521    }
    522 
    523    mState.size    = mState.source->getAttachmentSize(mState.imageIndex);
    524    mState.samples = mState.source->getAttachmentSamples(mState.imageIndex);
    525 
    526    if (IsTextureTarget(mState.sourceType))
    527    {
    528        mState.size.depth = 1;
    529    }
    530 
    531    return mImplementation->initialize(display);
    532 }
    533 
    534 bool Image::orphaned() const
    535 {
    536    return (mState.source == nullptr);
    537 }
    538 
    539 gl::InitState Image::sourceInitState() const
    540 {
    541    if (orphaned())
    542    {
    543        return mOrphanedAndNeedsInit ? gl::InitState::MayNeedInit : gl::InitState::Initialized;
    544    }
    545 
    546    return mState.source->initState(GL_NONE, mState.imageIndex);
    547 }
    548 
    549 void Image::setInitState(gl::InitState initState)
    550 {
    551    if (orphaned())
    552    {
    553        mOrphanedAndNeedsInit = false;
    554    }
    555 
    556    return mState.source->setInitState(GL_NONE, mState.imageIndex, initState);
    557 }
    558 
    559 Error Image::exportVkImage(void *vkImage, void *vkImageCreateInfo)
    560 {
    561    return mImplementation->exportVkImage(vkImage, vkImageCreateInfo);
    562 }
    563 
    564 void Image::notifySiblings(const ImageSibling *notifier, angle::SubjectMessage message)
    565 {
    566    if (mState.source && mState.source != notifier)
    567    {
    568        mState.source->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
    569    }
    570 
    571    std::unique_lock lock(mState.targetsLock);
    572    for (ImageSibling *target : mState.targets)
    573    {
    574        if (target != notifier)
    575        {
    576            target->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
    577        }
    578    }
    579 }
    580 
    581 }  // namespace egl