1 //
2 // Copyright 2018 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 // ImageEGL.cpp: Implements the rx::ImageEGL class.
8
9 #include "libANGLE/renderer/gl/egl/ImageEGL.h"
10
11 #include "common/utilities.h"
12 #include "libANGLE/Context.h"
13 #include "libANGLE/Display.h"
14 #include "libANGLE/renderer/gl/FunctionsGL.h"
15 #include "libANGLE/renderer/gl/RenderbufferGL.h"
16 #include "libANGLE/renderer/gl/StateManagerGL.h"
17 #include "libANGLE/renderer/gl/TextureGL.h"
18 #include "libANGLE/renderer/gl/egl/ContextEGL.h"
19 #include "libANGLE/renderer/gl/egl/ExternalImageSiblingEGL.h"
20 #include "libANGLE/renderer/gl/egl/FunctionsEGL.h"
21
22 namespace rx
23 {
24
ImageEGL(const egl::ImageState & state,const gl::Context * context,EGLenum target,const egl::AttributeMap & attribs,const FunctionsEGL * egl)25 ImageEGL::ImageEGL(const egl::ImageState &state,
26 const gl::Context *context,
27 EGLenum target,
28 const egl::AttributeMap &attribs,
29 const FunctionsEGL *egl)
30 : ImageGL(state),
31 mEGL(egl),
32 mContext(EGL_NO_CONTEXT),
33 mTarget(target),
34 mPreserveImage(false),
35 mImage(EGL_NO_IMAGE)
36 {
37 if (context)
38 {
39 mContext = GetImplAs<ContextEGL>(context)->getContext();
40 }
41 mPreserveImage = attribs.get(EGL_IMAGE_PRESERVED, EGL_FALSE) == EGL_TRUE;
42 }
43
~ImageEGL()44 ImageEGL::~ImageEGL()
45 {
46 mEGL->destroyImageKHR(mImage);
47 }
48
initialize(const egl::Display * display)49 egl::Error ImageEGL::initialize(const egl::Display *display)
50 {
51 EGLClientBuffer buffer = nullptr;
52 angle::FastVector<EGLint, 8> attributes;
53
54 if (egl::IsTextureTarget(mTarget))
55 {
56 attributes.push_back(EGL_GL_TEXTURE_LEVEL);
57 attributes.push_back(mState.imageIndex.getLevelIndex());
58
59 if (mState.imageIndex.has3DLayer())
60 {
61 attributes.push_back(EGL_GL_TEXTURE_ZOFFSET);
62 attributes.push_back(mState.imageIndex.getLayerIndex());
63 }
64
65 const TextureGL *textureGL = GetImplAs<TextureGL>(GetAs<gl::Texture>(mState.source));
66 buffer = gl_egl::GLObjectHandleToEGLClientBuffer(textureGL->getTextureID());
67 mNativeInternalFormat = textureGL->getNativeInternalFormat(mState.imageIndex);
68 }
69 else if (egl::IsRenderbufferTarget(mTarget))
70 {
71 const RenderbufferGL *renderbufferGL =
72 GetImplAs<RenderbufferGL>(GetAs<gl::Renderbuffer>(mState.source));
73 buffer = gl_egl::GLObjectHandleToEGLClientBuffer(renderbufferGL->getRenderbufferID());
74 mNativeInternalFormat = renderbufferGL->getNativeInternalFormat();
75 }
76 else if (egl::IsExternalImageTarget(mTarget))
77 {
78 const ExternalImageSiblingEGL *externalImageSibling =
79 GetImplAs<ExternalImageSiblingEGL>(GetAs<egl::ExternalImageSibling>(mState.source));
80 buffer = externalImageSibling->getBuffer();
81 mNativeInternalFormat = externalImageSibling->getFormat().info->sizedInternalFormat;
82
83 // Add any additional attributes this type of image sibline requires
84 std::vector<EGLint> tmp_attributes;
85 externalImageSibling->getImageCreationAttributes(&tmp_attributes);
86
87 attributes.reserve(attributes.size() + tmp_attributes.size());
88 for (EGLint attribute : tmp_attributes)
89 {
90 attributes.push_back(attribute);
91 }
92 }
93 else
94 {
95 UNREACHABLE();
96 }
97
98 attributes.push_back(EGL_IMAGE_PRESERVED);
99 attributes.push_back(mPreserveImage ? EGL_TRUE : EGL_FALSE);
100
101 attributes.push_back(EGL_NONE);
102
103 egl::Display::GetCurrentThreadUnlockedTailCall()->add([egl = mEGL, &image = mImage,
104 context = mContext, target = mTarget,
105 buffer, attributes](void *resultOut) {
106 image = egl->createImageKHR(context, target, buffer, attributes.data());
107
108 // If image creation failed, force the return value of eglCreateImage to EGL_NO_IMAGE. This
109 // won't delete this image object but a driver error is unexpected at this point.
110 if (image == EGL_NO_IMAGE)
111 {
112 ERR() << "eglCreateImage failed with " << gl::FmtHex(egl->getError());
113 *static_cast<EGLImage *>(resultOut) = EGL_NO_IMAGE;
114 }
115 });
116
117 return egl::NoError();
118 }
119
orphan(const gl::Context * context,egl::ImageSibling * sibling)120 angle::Result ImageEGL::orphan(const gl::Context *context, egl::ImageSibling *sibling)
121 {
122 // Nothing to do, the native EGLImage will orphan automatically.
123 return angle::Result::Continue;
124 }
125
setTexture2D(const gl::Context * context,gl::TextureType type,TextureGL * texture,GLenum * outInternalFormat)126 angle::Result ImageEGL::setTexture2D(const gl::Context *context,
127 gl::TextureType type,
128 TextureGL *texture,
129 GLenum *outInternalFormat)
130 {
131 const FunctionsGL *functionsGL = GetFunctionsGL(context);
132 StateManagerGL *stateManager = GetStateManagerGL(context);
133
134 // Make sure this texture is bound
135 stateManager->bindTexture(type, texture->getTextureID());
136
137 // Bind the image to the texture
138 functionsGL->eGLImageTargetTexture2DOES(ToGLenum(type), mImage);
139 *outInternalFormat = mNativeInternalFormat;
140
141 return angle::Result::Continue;
142 }
143
setRenderbufferStorage(const gl::Context * context,RenderbufferGL * renderbuffer,GLenum * outInternalFormat)144 angle::Result ImageEGL::setRenderbufferStorage(const gl::Context *context,
145 RenderbufferGL *renderbuffer,
146 GLenum *outInternalFormat)
147 {
148 const FunctionsGL *functionsGL = GetFunctionsGL(context);
149 StateManagerGL *stateManager = GetStateManagerGL(context);
150
151 // Make sure this renderbuffer is bound
152 stateManager->bindRenderbuffer(GL_RENDERBUFFER, renderbuffer->getRenderbufferID());
153
154 // Bind the image to the renderbuffer
155 functionsGL->eGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, mImage);
156 *outInternalFormat = mNativeInternalFormat;
157
158 return angle::Result::Continue;
159 }
160
161 } // namespace rx
162