blob: 6a0a2172245eee793ba1d9ca0133d109a82d1e4a [file] [log] [blame]
//
// Copyright (c) 2014 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.
//
// FramebufferAttachment.cpp: the gl::FramebufferAttachment class and its derived classes
// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108.
#include "libANGLE/FramebufferAttachment.h"
#include "common/utilities.h"
#include "libANGLE/Config.h"
#include "libANGLE/Context.h"
#include "libANGLE/Renderbuffer.h"
#include "libANGLE/Surface.h"
#include "libANGLE/Texture.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/FramebufferAttachmentObjectImpl.h"
#include "libANGLE/renderer/FramebufferImpl.h"
namespace gl
{
namespace
{
std::vector<Offset> TransformViewportOffsetArrayToVectorOfOffsets(const GLint *viewportOffsets,
GLsizei numViews)
{
const size_t numViewsAsSizeT = static_cast<size_t>(numViews);
std::vector<Offset> offsetVector;
offsetVector.reserve(numViewsAsSizeT);
for (size_t i = 0u; i < numViewsAsSizeT; ++i)
{
offsetVector.emplace_back(Offset(viewportOffsets[i * 2u], viewportOffsets[i * 2u + 1u], 0));
}
return offsetVector;
}
} // namespace
////// FramebufferAttachment::Target Implementation //////
const GLsizei FramebufferAttachment::kDefaultNumViews = 1;
const GLenum FramebufferAttachment::kDefaultMultiviewLayout = GL_NONE;
const GLint FramebufferAttachment::kDefaultBaseViewIndex = 0;
const GLint FramebufferAttachment::kDefaultViewportOffsets[2] = {0};
std::vector<Offset> FramebufferAttachment::GetDefaultViewportOffsetVector()
{
return TransformViewportOffsetArrayToVectorOfOffsets(
FramebufferAttachment::kDefaultViewportOffsets, FramebufferAttachment::kDefaultNumViews);
}
FramebufferAttachment::Target::Target() : mBinding(GL_NONE), mTextureIndex()
{
}
FramebufferAttachment::Target::Target(GLenum binding, const ImageIndex &imageIndex)
: mBinding(binding),
mTextureIndex(imageIndex)
{
}
FramebufferAttachment::Target::Target(const Target &other)
: mBinding(other.mBinding),
mTextureIndex(other.mTextureIndex)
{
}
FramebufferAttachment::Target &FramebufferAttachment::Target::operator=(const Target &other)
{
this->mBinding = other.mBinding;
this->mTextureIndex = other.mTextureIndex;
return *this;
}
////// FramebufferAttachment Implementation //////
FramebufferAttachment::FramebufferAttachment()
: mType(GL_NONE),
mResource(nullptr),
mNumViews(kDefaultNumViews),
mMultiviewLayout(kDefaultMultiviewLayout),
mBaseViewIndex(kDefaultBaseViewIndex),
mViewportOffsets(GetDefaultViewportOffsetVector())
{
}
FramebufferAttachment::FramebufferAttachment(const Context *context,
GLenum type,
GLenum binding,
const ImageIndex &textureIndex,
FramebufferAttachmentObject *resource)
: mResource(nullptr)
{
attach(context, type, binding, textureIndex, resource, kDefaultNumViews, kDefaultBaseViewIndex,
kDefaultMultiviewLayout, kDefaultViewportOffsets);
}
FramebufferAttachment::FramebufferAttachment(FramebufferAttachment &&other)
: FramebufferAttachment()
{
*this = std::move(other);
}
FramebufferAttachment &FramebufferAttachment::operator=(FramebufferAttachment &&other)
{
std::swap(mType, other.mType);
std::swap(mTarget, other.mTarget);
std::swap(mResource, other.mResource);
std::swap(mNumViews, other.mNumViews);
std::swap(mMultiviewLayout, other.mMultiviewLayout);
std::swap(mBaseViewIndex, other.mBaseViewIndex);
std::swap(mViewportOffsets, other.mViewportOffsets);
return *this;
}
FramebufferAttachment::~FramebufferAttachment()
{
ASSERT(!isAttached());
}
void FramebufferAttachment::detach(const Context *context)
{
mType = GL_NONE;
if (mResource != nullptr)
{
mResource->onDetach(context);
mResource = nullptr;
}
mNumViews = kDefaultNumViews;
mMultiviewLayout = kDefaultMultiviewLayout;
mBaseViewIndex = kDefaultBaseViewIndex;
mViewportOffsets = GetDefaultViewportOffsetVector();
// not technically necessary, could omit for performance
mTarget = Target();
}
void FramebufferAttachment::attach(const Context *context,
GLenum type,
GLenum binding,
const ImageIndex &textureIndex,
FramebufferAttachmentObject *resource,
GLsizei numViews,
GLuint baseViewIndex,
GLenum multiviewLayout,
const GLint *viewportOffsets)
{
if (resource == nullptr)
{
detach(context);
return;
}
mType = type;
mTarget = Target(binding, textureIndex);
mNumViews = numViews;
mBaseViewIndex = baseViewIndex;
mMultiviewLayout = multiviewLayout;
if (multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
{
mViewportOffsets = TransformViewportOffsetArrayToVectorOfOffsets(viewportOffsets, numViews);
}
else
{
mViewportOffsets = GetDefaultViewportOffsetVector();
}
resource->onAttach(context);
if (mResource != nullptr)
{
mResource->onDetach(context);
}
mResource = resource;
}
GLuint FramebufferAttachment::getRedSize() const
{
return getFormat().info->redBits;
}
GLuint FramebufferAttachment::getGreenSize() const
{
return getFormat().info->greenBits;
}
GLuint FramebufferAttachment::getBlueSize() const
{
return getFormat().info->blueBits;
}
GLuint FramebufferAttachment::getAlphaSize() const
{
return getFormat().info->alphaBits;
}
GLuint FramebufferAttachment::getDepthSize() const
{
return getFormat().info->depthBits;
}
GLuint FramebufferAttachment::getStencilSize() const
{
return getFormat().info->stencilBits;
}
GLenum FramebufferAttachment::getComponentType() const
{
return getFormat().info->componentType;
}
GLenum FramebufferAttachment::getColorEncoding() const
{
return getFormat().info->colorEncoding;
}
GLuint FramebufferAttachment::id() const
{
return mResource->getId();
}
const ImageIndex &FramebufferAttachment::getTextureImageIndex() const
{
ASSERT(type() == GL_TEXTURE);
return mTarget.textureIndex();
}
TextureTarget FramebufferAttachment::cubeMapFace() const
{
ASSERT(mType == GL_TEXTURE);
const auto &index = mTarget.textureIndex();
return index.getType() == TextureType::CubeMap ? index.getTarget() : TextureTarget::InvalidEnum;
}
GLint FramebufferAttachment::mipLevel() const
{
ASSERT(type() == GL_TEXTURE);
return mTarget.textureIndex().getLevelIndex();
}
GLint FramebufferAttachment::layer() const
{
ASSERT(mType == GL_TEXTURE);
const gl::ImageIndex &index = mTarget.textureIndex();
return (index.has3DLayer() ? index.getLayerIndex() : 0);
}
bool FramebufferAttachment::isLayered() const
{
return mTarget.textureIndex().isLayered();
}
GLsizei FramebufferAttachment::getNumViews() const
{
return mNumViews;
}
GLenum FramebufferAttachment::getMultiviewLayout() const
{
return mMultiviewLayout;
}
GLint FramebufferAttachment::getBaseViewIndex() const
{
return mBaseViewIndex;
}
const std::vector<Offset> &FramebufferAttachment::getMultiviewViewportOffsets() const
{
return mViewportOffsets;
}
Texture *FramebufferAttachment::getTexture() const
{
return rx::GetAs<Texture>(mResource);
}
Renderbuffer *FramebufferAttachment::getRenderbuffer() const
{
return rx::GetAs<Renderbuffer>(mResource);
}
const egl::Surface *FramebufferAttachment::getSurface() const
{
return rx::GetAs<egl::Surface>(mResource);
}
FramebufferAttachmentObject *FramebufferAttachment::getResource() const
{
return mResource;
}
bool FramebufferAttachment::operator==(const FramebufferAttachment &other) const
{
if (mResource != other.mResource || mType != other.mType || mNumViews != other.mNumViews ||
mMultiviewLayout != other.mMultiviewLayout || mBaseViewIndex != other.mBaseViewIndex ||
mViewportOffsets != other.mViewportOffsets)
{
return false;
}
if (mType == GL_TEXTURE && getTextureImageIndex() != other.getTextureImageIndex())
{
return false;
}
return true;
}
bool FramebufferAttachment::operator!=(const FramebufferAttachment &other) const
{
return !(*this == other);
}
InitState FramebufferAttachment::initState() const
{
return mResource ? mResource->initState(mTarget.textureIndex()) : InitState::Initialized;
}
Error FramebufferAttachment::initializeContents(const Context *context)
{
ASSERT(mResource);
ANGLE_TRY(mResource->initializeContents(context, mTarget.textureIndex()));
setInitState(InitState::Initialized);
return NoError();
}
void FramebufferAttachment::setInitState(InitState initState) const
{
ASSERT(mResource);
mResource->setInitState(mTarget.textureIndex(), initState);
}
////// FramebufferAttachmentObject Implementation //////
FramebufferAttachmentObject::FramebufferAttachmentObject()
{
}
FramebufferAttachmentObject::~FramebufferAttachmentObject()
{
}
Error FramebufferAttachmentObject::getAttachmentRenderTarget(
const Context *context,
GLenum binding,
const ImageIndex &imageIndex,
rx::FramebufferAttachmentRenderTarget **rtOut) const
{
return getAttachmentImpl()->getAttachmentRenderTarget(context, binding, imageIndex, rtOut);
}
void FramebufferAttachmentObject::onStorageChange(const gl::Context *context) const
{
return getAttachmentImpl()->onStateChange(context, angle::SubjectMessage::STORAGE_CHANGED);
}
angle::Subject *FramebufferAttachmentObject::getSubject() const
{
return getAttachmentImpl();
}
Error FramebufferAttachmentObject::initializeContents(const Context *context,
const ImageIndex &imageIndex)
{
ASSERT(context->isRobustResourceInitEnabled());
// Because gl::Texture cannot support tracking individual layer dirtiness, we only handle
// initializing entire mip levels for 2D array textures.
if (imageIndex.getType() == TextureType::_2DArray && imageIndex.hasLayer())
{
ImageIndex fullMipIndex =
ImageIndex::Make2DArray(imageIndex.getLevelIndex(), ImageIndex::kEntireLevel);
return getAttachmentImpl()->initializeContents(context, fullMipIndex);
}
else
{
return getAttachmentImpl()->initializeContents(context, imageIndex);
}
}
} // namespace gl