blob: 828f8623895a7de434e0b9a3227bd87cbfe73d42 [file]
//
// 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/ImageImpl.h"
namespace egl
{
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());
gl::Error error = mTargetOf->orphanSibling(this);
if (error.isError())
{
return error;
}
mTargetOf.set(nullptr);
}
else
{
for (auto &sourceImage : mSourcesOf)
{
gl::Error error = sourceImage->orphanSibling(this);
if (error.isError())
{
return error;
}
}
mSourcesOf.clear();
}
return gl::Error(GL_NO_ERROR);
}
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);
}
Image::Image(rx::ImageImpl *impl, EGLenum target, ImageSibling *buffer, const AttributeMap &attribs)
: RefCountObject(0),
mImplementation(impl),
mFormat(gl::Format::Invalid()),
mWidth(0),
mHeight(0),
mSamples(0),
mSource(),
mTargets()
{
ASSERT(mImplementation != nullptr);
ASSERT(buffer != nullptr);
mSource.set(buffer);
mSource->addImageSource(this);
if (IsTextureTarget(target))
{
gl::Texture *texture = rx::GetAs<gl::Texture>(mSource.get());
GLenum textureTarget = egl_gl::EGLImageTargetToGLTextureTarget(target);
size_t level = attribs.get(EGL_GL_TEXTURE_LEVEL_KHR, 0);
mFormat = texture->getFormat(textureTarget, level);
mWidth = texture->getWidth(textureTarget, level);
mHeight = texture->getHeight(textureTarget, level);
mSamples = 0;
}
else if (IsRenderbufferTarget(target))
{
gl::Renderbuffer *renderbuffer = rx::GetAs<gl::Renderbuffer>(mSource.get());
mFormat = renderbuffer->getFormat();
mWidth = renderbuffer->getWidth();
mHeight = renderbuffer->getHeight();
mSamples = renderbuffer->getSamples();
}
else
{
UNREACHABLE();
}
}
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(mTargets.empty());
// Tell the source that it is no longer used by this image
if (mSource.get() != nullptr)
{
mSource->removeImageSource(this);
mSource.set(nullptr);
}
}
void Image::addTargetSibling(ImageSibling *sibling)
{
mTargets.insert(sibling);
}
gl::Error Image::orphanSibling(ImageSibling *sibling)
{
// notify impl
gl::Error error = mImplementation->orphan(sibling);
if (mSource.get() == sibling)
{
// If the sibling is the source, it cannot be a target.
ASSERT(mTargets.find(sibling) == mTargets.end());
mSource.set(nullptr);
}
else
{
mTargets.erase(sibling);
}
return error;
}
const gl::Format &Image::getFormat() const
{
return mFormat;
}
size_t Image::getWidth() const
{
return mWidth;
}
size_t Image::getHeight() const
{
return mHeight;
}
size_t Image::getSamples() const
{
return mSamples;
}
rx::ImageImpl *Image::getImplementation()
{
return mImplementation;
}
const rx::ImageImpl *Image::getImplementation() const
{
return mImplementation;
}
} // namespace egl