1 //
2 // Copyright (c) 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/angletypes.h"
14 #include "libANGLE/formatutils.h"
15 #include "libANGLE/Texture.h"
16 #include "libANGLE/Renderbuffer.h"
17 #include "libANGLE/renderer/EGLImplFactory.h"
18 #include "libANGLE/renderer/ImageImpl.h"
19 
20 namespace egl
21 {
22 
23 namespace
24 {
GetImageIndex(EGLenum eglTarget,const egl::AttributeMap & attribs)25 gl::ImageIndex GetImageIndex(EGLenum eglTarget, const egl::AttributeMap &attribs)
26 {
27     if (eglTarget == EGL_GL_RENDERBUFFER)
28     {
29         return gl::ImageIndex::MakeInvalid();
30     }
31 
32     GLenum target = egl_gl::EGLImageTargetToGLTextureTarget(eglTarget);
33     GLint mip     = static_cast<GLint>(attribs.get(EGL_GL_TEXTURE_LEVEL_KHR, 0));
34     GLint layer   = static_cast<GLint>(attribs.get(EGL_GL_TEXTURE_ZOFFSET_KHR, 0));
35 
36     if (target == GL_TEXTURE_3D)
37     {
38         return gl::ImageIndex::Make3D(mip, layer);
39     }
40     else
41     {
42         ASSERT(layer == 0);
43         return gl::ImageIndex::MakeGeneric(target, mip);
44     }
45 }
46 }  // anonymous namespace
47 
ImageSibling(GLuint id)48 ImageSibling::ImageSibling(GLuint id)
49     : RefCountObject(id), FramebufferAttachmentObject(), mSourcesOf(), mTargetOf()
50 {
51 }
52 
~ImageSibling()53 ImageSibling::~ImageSibling()
54 {
55     // EGL images should hold a ref to their targets and siblings, a Texture should not be deletable
56     // while it is attached to an EGL image.
57     // Child class should orphan images before destruction.
58     ASSERT(mSourcesOf.empty());
59     ASSERT(mTargetOf.get() == nullptr);
60 }
61 
setTargetImage(const gl::Context * context,egl::Image * imageTarget)62 void ImageSibling::setTargetImage(const gl::Context *context, egl::Image *imageTarget)
63 {
64     ASSERT(imageTarget != nullptr);
65     mTargetOf.set(context, imageTarget);
66     imageTarget->addTargetSibling(this);
67 }
68 
orphanImages(const gl::Context * context)69 gl::Error ImageSibling::orphanImages(const gl::Context *context)
70 {
71     if (mTargetOf.get() != nullptr)
72     {
73         // Can't be a target and have sources.
74         ASSERT(mSourcesOf.empty());
75 
76         ANGLE_TRY(mTargetOf->orphanSibling(context, this));
77         mTargetOf.set(context, nullptr);
78     }
79     else
80     {
81         for (egl::Image *sourceImage : mSourcesOf)
82         {
83             ANGLE_TRY(sourceImage->orphanSibling(context, this));
84         }
85         mSourcesOf.clear();
86     }
87 
88     return gl::NoError();
89 }
90 
addImageSource(egl::Image * imageSource)91 void ImageSibling::addImageSource(egl::Image *imageSource)
92 {
93     ASSERT(imageSource != nullptr);
94     mSourcesOf.insert(imageSource);
95 }
96 
removeImageSource(egl::Image * imageSource)97 void ImageSibling::removeImageSource(egl::Image *imageSource)
98 {
99     ASSERT(mSourcesOf.find(imageSource) != mSourcesOf.end());
100     mSourcesOf.erase(imageSource);
101 }
102 
isEGLImageTarget() const103 bool ImageSibling::isEGLImageTarget() const
104 {
105     return (mTargetOf.get() != nullptr);
106 }
107 
sourceEGLImageInitState() const108 gl::InitState ImageSibling::sourceEGLImageInitState() const
109 {
110     ASSERT(isEGLImageTarget());
111     return mTargetOf->sourceInitState();
112 }
113 
setSourceEGLImageInitState(gl::InitState initState) const114 void ImageSibling::setSourceEGLImageInitState(gl::InitState initState) const
115 {
116     ASSERT(isEGLImageTarget());
117     mTargetOf->setInitState(initState);
118 }
119 
ImageState(EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)120 ImageState::ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs)
121     : imageIndex(GetImageIndex(target, attribs)), source(buffer), targets()
122 {
123 }
124 
~ImageState()125 ImageState::~ImageState()
126 {
127 }
128 
Image(rx::EGLImplFactory * factory,EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)129 Image::Image(rx::EGLImplFactory *factory,
130              EGLenum target,
131              ImageSibling *buffer,
132              const AttributeMap &attribs)
133     : RefCountObject(0),
134       mState(target, buffer, attribs),
135       mImplementation(factory->createImage(mState, target, attribs)),
136       mOrphanedAndNeedsInit(false)
137 {
138     ASSERT(mImplementation != nullptr);
139     ASSERT(buffer != nullptr);
140 
141     mState.source->addImageSource(this);
142 }
143 
onDestroy(const gl::Context * context)144 gl::Error Image::onDestroy(const gl::Context *context)
145 {
146     // All targets should hold a ref to the egl image and it should not be deleted until there are
147     // no siblings left.
148     ASSERT(mState.targets.empty());
149 
150     // Tell the source that it is no longer used by this image
151     if (mState.source.get() != nullptr)
152     {
153         mState.source->removeImageSource(this);
154         mState.source.set(context, nullptr);
155     }
156     return gl::NoError();
157 }
158 
~Image()159 Image::~Image()
160 {
161     SafeDelete(mImplementation);
162 }
163 
addTargetSibling(ImageSibling * sibling)164 void Image::addTargetSibling(ImageSibling *sibling)
165 {
166     mState.targets.insert(sibling);
167 }
168 
orphanSibling(const gl::Context * context,ImageSibling * sibling)169 gl::Error Image::orphanSibling(const gl::Context *context, ImageSibling *sibling)
170 {
171     // notify impl
172     ANGLE_TRY(mImplementation->orphan(context, sibling));
173 
174     if (mState.source.get() == sibling)
175     {
176         // If the sibling is the source, it cannot be a target.
177         ASSERT(mState.targets.find(sibling) == mState.targets.end());
178         mState.source.set(context, nullptr);
179         mOrphanedAndNeedsInit =
180             (sibling->initState(mState.imageIndex) == gl::InitState::MayNeedInit);
181     }
182     else
183     {
184         mState.targets.erase(sibling);
185     }
186 
187     return gl::NoError();
188 }
189 
getFormat() const190 const gl::Format &Image::getFormat() const
191 {
192     return mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex);
193 }
194 
getWidth() const195 size_t Image::getWidth() const
196 {
197     return mState.source->getAttachmentSize(mState.imageIndex).width;
198 }
199 
getHeight() const200 size_t Image::getHeight() const
201 {
202     return mState.source->getAttachmentSize(mState.imageIndex).height;
203 }
204 
getSamples() const205 size_t Image::getSamples() const
206 {
207     return mState.source->getAttachmentSamples(mState.imageIndex);
208 }
209 
getImplementation() const210 rx::ImageImpl *Image::getImplementation() const
211 {
212     return mImplementation;
213 }
214 
initialize()215 Error Image::initialize()
216 {
217     return mImplementation->initialize();
218 }
219 
orphaned() const220 bool Image::orphaned() const
221 {
222     return (mState.source.get() == nullptr);
223 }
224 
sourceInitState() const225 gl::InitState Image::sourceInitState() const
226 {
227     if (orphaned())
228     {
229         return mOrphanedAndNeedsInit ? gl::InitState::MayNeedInit : gl::InitState::Initialized;
230     }
231 
232     return mState.source->initState(mState.imageIndex);
233 }
234 
setInitState(gl::InitState initState)235 void Image::setInitState(gl::InitState initState)
236 {
237     if (orphaned())
238     {
239         mOrphanedAndNeedsInit = false;
240     }
241 
242     return mState.source->setInitState(mState.imageIndex, initState);
243 }
244 
245 }  // namespace egl
246