text: //
  // Copyright 2018 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.
  //
  
  // ImageEGL.cpp: Implements the rx::ImageEGL class.
  
  #include "libANGLE/renderer/gl/egl/ImageEGL.h"
  
  #include "common/utilities.h"
  #include "libANGLE/Context.h"
  #include "libANGLE/renderer/gl/FunctionsGL.h"
  #include "libANGLE/renderer/gl/RenderbufferGL.h"
  #include "libANGLE/renderer/gl/StateManagerGL.h"
  #include "libANGLE/renderer/gl/TextureGL.h"
  #include "libANGLE/renderer/gl/egl/ContextEGL.h"
  #include "libANGLE/renderer/gl/egl/ExternalImageSiblingEGL.h"
  #include "libANGLE/renderer/gl/egl/FunctionsEGL.h"
  
  namespace rx
  {
  
  ImageEGL::ImageEGL(const egl::ImageState &state,
                     const gl::Context *context,
                     EGLenum target,
                     const egl::AttributeMap &attribs,
                     const FunctionsEGL *egl)
      : ImageGL(state),
        mEGL(egl),
        mContext(EGL_NO_CONTEXT),
        mTarget(target),
        mPreserveImage(false),
        mImage(EGL_NO_IMAGE)
  {
      if (context)
      {
          mContext = GetImplAs<ContextEGL>(context)->getContext();
      }
      mPreserveImage = attribs.get(EGL_IMAGE_PRESERVED, EGL_FALSE) == EGL_TRUE;
  }
  
  ImageEGL::~ImageEGL()
  {
      mEGL->destroyImageKHR(mImage);
  }
  
  egl::Error ImageEGL::initialize(const egl::Display *display)
  {
      EGLClientBuffer buffer = nullptr;
      std::vector<EGLint> attributes;
  
      if (egl::IsTextureTarget(mTarget))
      {
          attributes.push_back(EGL_GL_TEXTURE_LEVEL);
          attributes.push_back(mState.imageIndex.getLevelIndex());
  
          if (mState.imageIndex.has3DLayer())
          {
              attributes.push_back(EGL_GL_TEXTURE_ZOFFSET);
              attributes.push_back(mState.imageIndex.getLayerIndex());
          }
  
          const TextureGL *textureGL = GetImplAs<TextureGL>(GetAs<gl::Texture>(mState.source));
          buffer                = gl_egl::GLObjectHandleToEGLClientBuffer(textureGL->getTextureID());
          mNativeInternalFormat = textureGL->getNativeInternalFormat(mState.imageIndex);
      }
      else if (egl::IsRenderbufferTarget(mTarget))
      {
          const RenderbufferGL *renderbufferGL =
              GetImplAs<RenderbufferGL>(GetAs<gl::Renderbuffer>(mState.source));
          buffer = gl_egl::GLObjectHandleToEGLClientBuffer(renderbufferGL->getRenderbufferID());
          mNativeInternalFormat = renderbufferGL->getNativeInternalFormat();
      }
      else if (egl::IsExternalImageTarget(mTarget))
      {
          const ExternalImageSiblingEGL *externalImageSibling =
              GetImplAs<ExternalImageSiblingEGL>(GetAs<egl::ExternalImageSibling>(mState.source));
          buffer                = externalImageSibling->getBuffer();
          mNativeInternalFormat = externalImageSibling->getFormat().info->sizedInternalFormat;
  
          // Add any additional attributes this type of image sibline requires
          externalImageSibling->getImageCreationAttributes(&attributes);
      }
      else
      {
          UNREACHABLE();
      }
  
      attributes.push_back(EGL_IMAGE_PRESERVED);
      attributes.push_back(mPreserveImage ? EGL_TRUE : EGL_FALSE);
  
      attributes.push_back(EGL_NONE);
  
      mImage = mEGL->createImageKHR(mContext, mTarget, buffer, attributes.data());
      if (mImage == EGL_NO_IMAGE)
      {
          return egl::EglBadAlloc() << "eglCreateImage failed with " << egl::Error(mEGL->getError());
      }
  
      return egl::NoError();
  }
  
  angle::Result ImageEGL::orphan(const gl::Context *context, egl::ImageSibling *sibling)
  {
      // Nothing to do, the native EGLImage will orphan automatically.
      return angle::Result::Continue;
  }
  
  angle::Result ImageEGL::setTexture2D(const gl::Context *context,
                                       gl::TextureType type,
                                       TextureGL *texture,
                                       GLenum *outInternalFormat)
  {
      const FunctionsGL *functionsGL = GetFunctionsGL(context);
      StateManagerGL *stateManager   = GetStateManagerGL(context);
  
      // Make sure this texture is bound
      stateManager->bindTexture(type, texture->getTextureID());
  
      // Bind the image to the texture
      functionsGL->eGLImageTargetTexture2DOES(ToGLenum(type), mImage);
      *outInternalFormat = mNativeInternalFormat;
  
      return angle::Result::Continue;
  }
  
  angle::Result ImageEGL::setRenderbufferStorage(const gl::Context *context,
                                                 RenderbufferGL *renderbuffer,
                                                 GLenum *outInternalFormat)
  {
      const FunctionsGL *functionsGL = GetFunctionsGL(context);
      StateManagerGL *stateManager   = GetStateManagerGL(context);
  
      // Make sure this renderbuffer is bound
      stateManager->bindRenderbuffer(GL_RENDERBUFFER, renderbuffer->getRenderbufferID());
  
      // Bind the image to the renderbuffer
      functionsGL->eGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, mImage);
      *outInternalFormat = mNativeInternalFormat;
  
      return angle::Result::Continue;
  }
  
  }  // namespace rx
  