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 {
GetImageIndex(EGLenum eglTarget,const egl::AttributeMap & attribs)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
DisplayFromContext(const gl::Context * context)48 const Display *DisplayFromContext(const gl::Context *context)
49 {
50 return (context ? context->getDisplay() : nullptr);
51 }
52 } // anonymous namespace
53
ImageSibling()54 ImageSibling::ImageSibling() : FramebufferAttachmentObject(), mSourcesOf(), mTargetOf() {}
55
~ImageSibling()56 ImageSibling::~ImageSibling()
57 {
58 // EGL images should hold a ref to their targets and siblings, a Texture should not be deletable
59 // while it is attached to an EGL image.
60 // Child class should orphan images before destruction.
61 ASSERT(mSourcesOf.empty());
62 ASSERT(mTargetOf.get() == nullptr);
63 }
64
setTargetImage(const gl::Context * context,egl::Image * imageTarget)65 void ImageSibling::setTargetImage(const gl::Context *context, egl::Image *imageTarget)
66 {
67 ASSERT(imageTarget != nullptr);
68 mTargetOf.set(DisplayFromContext(context), imageTarget);
69 imageTarget->addTargetSibling(this);
70 }
71
orphanImages(const gl::Context * context)72 angle::Result ImageSibling::orphanImages(const gl::Context *context)
73 {
74 if (mTargetOf.get() != nullptr)
75 {
76 // Can't be a target and have sources.
77 ASSERT(mSourcesOf.empty());
78
79 ANGLE_TRY(mTargetOf->orphanSibling(context, this));
80 mTargetOf.set(DisplayFromContext(context), nullptr);
81 }
82 else
83 {
84 for (Image *sourceImage : mSourcesOf)
85 {
86 ANGLE_TRY(sourceImage->orphanSibling(context, this));
87 }
88 mSourcesOf.clear();
89 }
90
91 return angle::Result::Continue;
92 }
93
addImageSource(egl::Image * imageSource)94 void ImageSibling::addImageSource(egl::Image *imageSource)
95 {
96 ASSERT(imageSource != nullptr);
97 mSourcesOf.insert(imageSource);
98 }
99
removeImageSource(egl::Image * imageSource)100 void ImageSibling::removeImageSource(egl::Image *imageSource)
101 {
102 ASSERT(mSourcesOf.find(imageSource) != mSourcesOf.end());
103 mSourcesOf.erase(imageSource);
104 }
105
isEGLImageTarget() const106 bool ImageSibling::isEGLImageTarget() const
107 {
108 return (mTargetOf.get() != nullptr);
109 }
110
sourceEGLImageInitState() const111 gl::InitState ImageSibling::sourceEGLImageInitState() const
112 {
113 ASSERT(isEGLImageTarget());
114 return mTargetOf->sourceInitState();
115 }
116
setSourceEGLImageInitState(gl::InitState initState) const117 void ImageSibling::setSourceEGLImageInitState(gl::InitState initState) const
118 {
119 ASSERT(isEGLImageTarget());
120 mTargetOf->setInitState(initState);
121 }
122
isRenderable(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex) const123 bool ImageSibling::isRenderable(const gl::Context *context,
124 GLenum binding,
125 const gl::ImageIndex &imageIndex) const
126 {
127 ASSERT(isEGLImageTarget());
128 return mTargetOf->isRenderable(context);
129 }
130
notifySiblings(angle::SubjectMessage message)131 void ImageSibling::notifySiblings(angle::SubjectMessage message)
132 {
133 if (mTargetOf.get())
134 {
135 mTargetOf->notifySiblings(this, message);
136 }
137 for (Image *source : mSourcesOf)
138 {
139 source->notifySiblings(this, message);
140 }
141 }
142
ExternalImageSibling(rx::EGLImplFactory * factory,const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const AttributeMap & attribs)143 ExternalImageSibling::ExternalImageSibling(rx::EGLImplFactory *factory,
144 const gl::Context *context,
145 EGLenum target,
146 EGLClientBuffer buffer,
147 const AttributeMap &attribs)
148 : mImplementation(factory->createExternalImageSibling(context, target, buffer, attribs))
149 {}
150
151 ExternalImageSibling::~ExternalImageSibling() = default;
152
onDestroy(const egl::Display * display)153 void ExternalImageSibling::onDestroy(const egl::Display *display)
154 {
155 mImplementation->onDestroy(display);
156 }
157
initialize(const egl::Display * display)158 Error ExternalImageSibling::initialize(const egl::Display *display)
159 {
160 return mImplementation->initialize(display);
161 }
162
getAttachmentSize(const gl::ImageIndex & imageIndex) const163 gl::Extents ExternalImageSibling::getAttachmentSize(const gl::ImageIndex &imageIndex) const
164 {
165 return mImplementation->getSize();
166 }
167
getAttachmentFormat(GLenum binding,const gl::ImageIndex & imageIndex) const168 gl::Format ExternalImageSibling::getAttachmentFormat(GLenum binding,
169 const gl::ImageIndex &imageIndex) const
170 {
171 return mImplementation->getFormat();
172 }
173
getAttachmentSamples(const gl::ImageIndex & imageIndex) const174 GLsizei ExternalImageSibling::getAttachmentSamples(const gl::ImageIndex &imageIndex) const
175 {
176 return static_cast<GLsizei>(mImplementation->getSamples());
177 }
178
isRenderable(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex) const179 bool ExternalImageSibling::isRenderable(const gl::Context *context,
180 GLenum binding,
181 const gl::ImageIndex &imageIndex) const
182 {
183 return mImplementation->isRenderable(context);
184 }
185
isTextureable(const gl::Context * context) const186 bool ExternalImageSibling::isTextureable(const gl::Context *context) const
187 {
188 return mImplementation->isTexturable(context);
189 }
190
onAttach(const gl::Context * context)191 void ExternalImageSibling::onAttach(const gl::Context *context) {}
192
onDetach(const gl::Context * context)193 void ExternalImageSibling::onDetach(const gl::Context *context) {}
194
getId() const195 GLuint ExternalImageSibling::getId() const
196 {
197 UNREACHABLE();
198 return 0;
199 }
200
initState(const gl::ImageIndex & imageIndex) const201 gl::InitState ExternalImageSibling::initState(const gl::ImageIndex &imageIndex) const
202 {
203 return gl::InitState::Initialized;
204 }
205
setInitState(const gl::ImageIndex & imageIndex,gl::InitState initState)206 void ExternalImageSibling::setInitState(const gl::ImageIndex &imageIndex, gl::InitState initState)
207 {}
208
getImplementation() const209 rx::ExternalImageSiblingImpl *ExternalImageSibling::getImplementation() const
210 {
211 return mImplementation.get();
212 }
213
getAttachmentImpl() const214 rx::FramebufferAttachmentObjectImpl *ExternalImageSibling::getAttachmentImpl() const
215 {
216 return mImplementation.get();
217 }
218
ImageState(EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)219 ImageState::ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs)
220 : label(nullptr),
221 target(target),
222 imageIndex(GetImageIndex(target, attribs)),
223 source(buffer),
224 targets(),
225 format(GL_NONE),
226 size(),
227 samples(),
228 sourceType(target),
229 colorspace(
230 static_cast<EGLenum>(attribs.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_DEFAULT_EXT)))
231 {}
232
~ImageState()233 ImageState::~ImageState() {}
234
Image(rx::EGLImplFactory * factory,const gl::Context * context,EGLenum target,ImageSibling * buffer,const AttributeMap & attribs)235 Image::Image(rx::EGLImplFactory *factory,
236 const gl::Context *context,
237 EGLenum target,
238 ImageSibling *buffer,
239 const AttributeMap &attribs)
240 : mState(target, buffer, attribs),
241 mImplementation(factory->createImage(mState, context, target, attribs)),
242 mOrphanedAndNeedsInit(false)
243 {
244 ASSERT(mImplementation != nullptr);
245 ASSERT(buffer != nullptr);
246
247 mState.source->addImageSource(this);
248 }
249
onDestroy(const Display * display)250 void Image::onDestroy(const Display *display)
251 {
252 // All targets should hold a ref to the egl image and it should not be deleted until there are
253 // no siblings left.
254 ASSERT(mState.targets.empty());
255
256 // Make sure the implementation gets a chance to clean up before we delete the source.
257 mImplementation->onDestroy(display);
258
259 // Tell the source that it is no longer used by this image
260 if (mState.source != nullptr)
261 {
262 mState.source->removeImageSource(this);
263
264 // If the source is an external object, delete it
265 if (IsExternalImageTarget(mState.sourceType))
266 {
267 ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source);
268 externalSibling->onDestroy(display);
269 delete externalSibling;
270 }
271
272 mState.source = nullptr;
273 }
274 }
275
~Image()276 Image::~Image()
277 {
278 SafeDelete(mImplementation);
279 }
280
setLabel(EGLLabelKHR label)281 void Image::setLabel(EGLLabelKHR label)
282 {
283 mState.label = label;
284 }
285
getLabel() const286 EGLLabelKHR Image::getLabel() const
287 {
288 return mState.label;
289 }
290
addTargetSibling(ImageSibling * sibling)291 void Image::addTargetSibling(ImageSibling *sibling)
292 {
293 mState.targets.insert(sibling);
294 }
295
orphanSibling(const gl::Context * context,ImageSibling * sibling)296 angle::Result Image::orphanSibling(const gl::Context *context, ImageSibling *sibling)
297 {
298 ASSERT(sibling != nullptr);
299
300 // notify impl
301 ANGLE_TRY(mImplementation->orphan(context, sibling));
302
303 if (mState.source == sibling)
304 {
305 // The external source of an image cannot be redefined so it cannot be orpahend.
306 ASSERT(!IsExternalImageTarget(mState.sourceType));
307
308 // If the sibling is the source, it cannot be a target.
309 ASSERT(mState.targets.find(sibling) == mState.targets.end());
310 mState.source = nullptr;
311 mOrphanedAndNeedsInit =
312 (sibling->initState(mState.imageIndex) == gl::InitState::MayNeedInit);
313 }
314 else
315 {
316 mState.targets.erase(sibling);
317 }
318
319 return angle::Result::Continue;
320 }
321
getFormat() const322 const gl::Format &Image::getFormat() const
323 {
324 return mState.format;
325 }
326
isRenderable(const gl::Context * context) const327 bool Image::isRenderable(const gl::Context *context) const
328 {
329 if (IsTextureTarget(mState.sourceType))
330 {
331 return mState.format.info->textureAttachmentSupport(context->getClientVersion(),
332 context->getExtensions());
333 }
334 else if (IsRenderbufferTarget(mState.sourceType))
335 {
336 return mState.format.info->renderbufferSupport(context->getClientVersion(),
337 context->getExtensions());
338 }
339 else if (IsExternalImageTarget(mState.sourceType))
340 {
341 ASSERT(mState.source != nullptr);
342 return mState.source->isRenderable(context, GL_NONE, gl::ImageIndex());
343 }
344
345 UNREACHABLE();
346 return false;
347 }
348
isTexturable(const gl::Context * context) const349 bool Image::isTexturable(const gl::Context *context) const
350 {
351 if (IsTextureTarget(mState.sourceType))
352 {
353 return mState.format.info->textureSupport(context->getClientVersion(),
354 context->getExtensions());
355 }
356 else if (IsRenderbufferTarget(mState.sourceType))
357 {
358 return true;
359 }
360 else if (IsExternalImageTarget(mState.sourceType))
361 {
362 ASSERT(mState.source != nullptr);
363 return rx::GetAs<ExternalImageSibling>(mState.source)->isTextureable(context);
364 }
365
366 UNREACHABLE();
367 return false;
368 }
369
getWidth() const370 size_t Image::getWidth() const
371 {
372 return mState.size.width;
373 }
374
getHeight() const375 size_t Image::getHeight() const
376 {
377 return mState.size.height;
378 }
379
getSamples() const380 size_t Image::getSamples() const
381 {
382 return mState.samples;
383 }
384
getImplementation() const385 rx::ImageImpl *Image::getImplementation() const
386 {
387 return mImplementation;
388 }
389
initialize(const Display * display)390 Error Image::initialize(const Display *display)
391 {
392 if (IsExternalImageTarget(mState.sourceType))
393 {
394 ANGLE_TRY(rx::GetAs<ExternalImageSibling>(mState.source)->initialize(display));
395 }
396
397 mState.format = mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex);
398
399 if (mState.colorspace != EGL_GL_COLORSPACE_DEFAULT_EXT)
400 {
401 GLenum nonLinearFormat = mState.format.info->sizedInternalFormat;
402 if (!gl::ColorspaceFormatOverride(mState.colorspace, &nonLinearFormat))
403 {
404 // the colorspace format is not supported
405 return egl::EglBadMatch();
406 }
407 mState.format = gl::Format(nonLinearFormat);
408 }
409
410 mState.size = mState.source->getAttachmentSize(mState.imageIndex);
411 mState.samples = mState.source->getAttachmentSamples(mState.imageIndex);
412
413 return mImplementation->initialize(display);
414 }
415
orphaned() const416 bool Image::orphaned() const
417 {
418 return (mState.source == nullptr);
419 }
420
sourceInitState() const421 gl::InitState Image::sourceInitState() const
422 {
423 if (orphaned())
424 {
425 return mOrphanedAndNeedsInit ? gl::InitState::MayNeedInit : gl::InitState::Initialized;
426 }
427
428 return mState.source->initState(mState.imageIndex);
429 }
430
setInitState(gl::InitState initState)431 void Image::setInitState(gl::InitState initState)
432 {
433 if (orphaned())
434 {
435 mOrphanedAndNeedsInit = false;
436 }
437
438 return mState.source->setInitState(mState.imageIndex, initState);
439 }
440
notifySiblings(const ImageSibling * notifier,angle::SubjectMessage message)441 void Image::notifySiblings(const ImageSibling *notifier, angle::SubjectMessage message)
442 {
443 if (mState.source && mState.source != notifier)
444 {
445 mState.source->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
446 }
447
448 for (ImageSibling *target : mState.targets)
449 {
450 if (target != notifier)
451 {
452 target->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message);
453 }
454 }
455 }
456
457 } // namespace egl
458