blob: 194fad17c6afc16ffcf1981acd5a3ff4c67521b7 [file] [log] [blame]
//
// Copyright (c) 2015 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.
//
// Image.cpp: Implements the egl::Image class representing the EGLimage object.
#include "libANGLE/Image.h"
#include "common/debug.h"
#include "common/utilities.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/Texture.h"
#include "libANGLE/Renderbuffer.h"
#include "libANGLE/renderer/EGLImplFactory.h"
#include "libANGLE/renderer/ImageImpl.h"
namespace egl
{
namespace
{
gl::ImageIndex GetImageIndex(EGLenum eglTarget, const egl::AttributeMap &attribs)
{
if (eglTarget == EGL_GL_RENDERBUFFER)
{
return gl::ImageIndex::MakeInvalid();
}
GLenum target = egl_gl::EGLImageTargetToGLTextureTarget(eglTarget);
GLint mip = static_cast<GLint>(attribs.get(EGL_GL_TEXTURE_LEVEL_KHR, 0));
GLint layer = static_cast<GLint>(attribs.get(EGL_GL_TEXTURE_ZOFFSET_KHR, 0));
if (target == GL_TEXTURE_3D)
{
return gl::ImageIndex::Make3D(mip, layer);
}
else
{
ASSERT(layer == 0);
return gl::ImageIndex::MakeGeneric(target, mip);
}
}
} // anonymous namespace
ImageSibling::ImageSibling(GLuint id) : RefCountObject(id), mSourcesOf(), mTargetOf()
{
}
ImageSibling::~ImageSibling()
{
// EGL images should hold a ref to their targets and siblings, a Texture should not be deletable
// while it is attached to an EGL image.
ASSERT(mSourcesOf.empty());
orphanImages();
}
void ImageSibling::setTargetImage(egl::Image *imageTarget)
{
ASSERT(imageTarget != nullptr);
mTargetOf.set(imageTarget);
imageTarget->addTargetSibling(this);
}
gl::Error ImageSibling::orphanImages()
{
if (mTargetOf.get() != nullptr)
{
// Can't be a target and have sources.
ASSERT(mSourcesOf.empty());
ANGLE_TRY(mTargetOf->orphanSibling(this));
mTargetOf.set(nullptr);
}
else
{
for (auto &sourceImage : mSourcesOf)
{
ANGLE_TRY(sourceImage->orphanSibling(this));
}
mSourcesOf.clear();
}
return gl::NoError();
}
void ImageSibling::addImageSource(egl::Image *imageSource)
{
ASSERT(imageSource != nullptr);
mSourcesOf.insert(imageSource);
}
void ImageSibling::removeImageSource(egl::Image *imageSource)
{
ASSERT(mSourcesOf.find(imageSource) != mSourcesOf.end());
mSourcesOf.erase(imageSource);
}
ImageState::ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs)
: imageIndex(GetImageIndex(target, attribs)), source(), targets()
{
source.set(buffer);
}
Image::Image(rx::EGLImplFactory *factory,
EGLenum target,
ImageSibling *buffer,
const AttributeMap &attribs)
: RefCountObject(0),
mState(target, buffer, attribs),
mImplementation(factory->createImage(mState, target, attribs))
{
ASSERT(mImplementation != nullptr);
ASSERT(buffer != nullptr);
mState.source->addImageSource(this);
}
Image::~Image()
{
SafeDelete(mImplementation);
// All targets should hold a ref to the egl image and it should not be deleted until there are
// no siblings left.
ASSERT(mState.targets.empty());
// Tell the source that it is no longer used by this image
if (mState.source.get() != nullptr)
{
mState.source->removeImageSource(this);
mState.source.set(nullptr);
}
}
void Image::addTargetSibling(ImageSibling *sibling)
{
mState.targets.insert(sibling);
}
gl::Error Image::orphanSibling(ImageSibling *sibling)
{
// notify impl
ANGLE_TRY(mImplementation->orphan(sibling));
if (mState.source.get() == sibling)
{
// If the sibling is the source, it cannot be a target.
ASSERT(mState.targets.find(sibling) == mState.targets.end());
mState.source.set(nullptr);
}
else
{
mState.targets.erase(sibling);
}
return gl::NoError();
}
const gl::Format &Image::getFormat() const
{
return mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex);
}
size_t Image::getWidth() const
{
return mState.source->getAttachmentSize(mState.imageIndex).width;
}
size_t Image::getHeight() const
{
return mState.source->getAttachmentSize(mState.imageIndex).height;
}
size_t Image::getSamples() const
{
return mState.source->getAttachmentSamples(mState.imageIndex);
}
rx::ImageImpl *Image::getImplementation() const
{
return mImplementation;
}
Error Image::initialize()
{
return mImplementation->initialize();
}
} // namespace egl