blob: 200038867f34a6faee35ff452372659f3a71d9a3 [file] [log] [blame]
//
// Copyright 2002 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.
//
// Renderbuffer.cpp: Implements the renderer-agnostic gl::Renderbuffer class,
// GL renderbuffer objects and related functionality.
// [OpenGL ES 2.0.24] section 4.4.3 page 108.
#include "libANGLE/Renderbuffer.h"
#include "common/utilities.h"
#include "libANGLE/Context.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/Image.h"
#include "libANGLE/Renderbuffer.h"
#include "libANGLE/Texture.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/GLImplFactory.h"
#include "libANGLE/renderer/d3d/RenderTargetD3D.h"
namespace gl
{
namespace
{
angle::SubjectIndex kRenderbufferImplSubjectIndex = 0;
InitState DetermineInitState(const Context *context)
{
return (context && context->isRobustResourceInitEnabled()) ? InitState::MayNeedInit
: InitState::Initialized;
}
} // namespace
// RenderbufferState implementation.
RenderbufferState::RenderbufferState()
: mWidth(0),
mHeight(0),
mFormat(GL_RGBA4),
mSamples(0),
mMultisamplingMode(MultisamplingMode::Regular),
mHasProtectedContent(false),
mInitState(InitState::Initialized)
{}
RenderbufferState::~RenderbufferState() {}
GLsizei RenderbufferState::getWidth() const
{
return mWidth;
}
GLsizei RenderbufferState::getHeight() const
{
return mHeight;
}
const Format &RenderbufferState::getFormat() const
{
return mFormat;
}
GLsizei RenderbufferState::getSamples() const
{
return mSamples;
}
MultisamplingMode RenderbufferState::getMultisamplingMode() const
{
return mMultisamplingMode;
}
InitState RenderbufferState::getInitState() const
{
return mInitState;
}
void RenderbufferState::update(GLsizei width,
GLsizei height,
const Format &format,
GLsizei samples,
MultisamplingMode multisamplingMode,
InitState initState)
{
mWidth = width;
mHeight = height;
mFormat = format;
mSamples = samples;
mMultisamplingMode = multisamplingMode;
mInitState = initState;
mHasProtectedContent = false;
}
void RenderbufferState::setProtectedContent(bool hasProtectedContent)
{
mHasProtectedContent = hasProtectedContent;
}
// Renderbuffer implementation.
Renderbuffer::Renderbuffer(rx::GLImplFactory *implFactory, RenderbufferID id)
: RefCountObject(implFactory->generateSerial(), id),
mState(),
mImplementation(implFactory->createRenderbuffer(mState)),
mLabel(),
mImplObserverBinding(this, kRenderbufferImplSubjectIndex)
{
mImplObserverBinding.bind(mImplementation.get());
}
void Renderbuffer::onDestroy(const Context *context)
{
egl::RefCountObjectReleaser<egl::Image> releaseImage;
(void)orphanImages(context, &releaseImage);
if (mImplementation)
{
mImplementation->onDestroy(context);
}
}
Renderbuffer::~Renderbuffer() {}
void Renderbuffer::setLabel(const Context *context, const std::string &label)
{
mLabel = label;
}
const std::string &Renderbuffer::getLabel() const
{
return mLabel;
}
angle::Result Renderbuffer::setStorage(const Context *context,
GLenum internalformat,
GLsizei width,
GLsizei height)
{
egl::RefCountObjectReleaser<egl::Image> releaseImage;
ANGLE_TRY(orphanImages(context, &releaseImage));
ANGLE_TRY(mImplementation->setStorage(context, internalformat, width, height));
mState.update(width, height, Format(internalformat), 0, MultisamplingMode::Regular,
DetermineInitState(context));
onStateChange(angle::SubjectMessage::SubjectChanged);
return angle::Result::Continue;
}
angle::Result Renderbuffer::setStorageMultisample(const Context *context,
GLsizei samplesIn,
GLenum internalformat,
GLsizei width,
GLsizei height,
MultisamplingMode mode)
{
egl::RefCountObjectReleaser<egl::Image> releaseImage;
ANGLE_TRY(orphanImages(context, &releaseImage));
// Potentially adjust "samplesIn" to a supported value
const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
GLsizei samples = formatCaps.getNearestSamples(samplesIn);
ANGLE_TRY(mImplementation->setStorageMultisample(context, samples, internalformat, width,
height, mode));
mState.update(width, height, Format(internalformat), samples, mode,
DetermineInitState(context));
onStateChange(angle::SubjectMessage::SubjectChanged);
return angle::Result::Continue;
}
angle::Result Renderbuffer::setStorageEGLImageTarget(const Context *context, egl::Image *image)
{
egl::RefCountObjectReleaser<egl::Image> releaseImage;
ANGLE_TRY(orphanImages(context, &releaseImage));
ANGLE_TRY(mImplementation->setStorageEGLImageTarget(context, image));
setTargetImage(context, image);
mState.update(static_cast<GLsizei>(image->getWidth()), static_cast<GLsizei>(image->getHeight()),
Format(image->getFormat()), 0, MultisamplingMode::Regular,
image->sourceInitState());
mState.setProtectedContent(image->hasProtectedContent());
onStateChange(angle::SubjectMessage::SubjectChanged);
return angle::Result::Continue;
}
angle::Result Renderbuffer::copyRenderbufferSubData(Context *context,
const gl::Renderbuffer *srcBuffer,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{
ANGLE_TRY(mImplementation->copyRenderbufferSubData(context, srcBuffer, srcLevel, srcX, srcY,
srcZ, dstLevel, dstX, dstY, dstZ, srcWidth,
srcHeight, srcDepth));
return angle::Result::Continue;
}
angle::Result Renderbuffer::copyTextureSubData(Context *context,
const gl::Texture *srcTexture,
GLint srcLevel,
GLint srcX,
GLint srcY,
GLint srcZ,
GLint dstLevel,
GLint dstX,
GLint dstY,
GLint dstZ,
GLsizei srcWidth,
GLsizei srcHeight,
GLsizei srcDepth)
{
ANGLE_TRY(mImplementation->copyTextureSubData(context, srcTexture, srcLevel, srcX, srcY, srcZ,
dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight,
srcDepth));
return angle::Result::Continue;
}
rx::RenderbufferImpl *Renderbuffer::getImplementation() const
{
ASSERT(mImplementation);
return mImplementation.get();
}
GLsizei Renderbuffer::getWidth() const
{
return mState.mWidth;
}
GLsizei Renderbuffer::getHeight() const
{
return mState.mHeight;
}
const Format &Renderbuffer::getFormat() const
{
return mState.mFormat;
}
GLsizei Renderbuffer::getSamples() const
{
return mState.mMultisamplingMode == MultisamplingMode::Regular ? mState.mSamples : 0;
}
MultisamplingMode Renderbuffer::getMultisamplingMode() const
{
return mState.mMultisamplingMode;
}
GLuint Renderbuffer::getRedSize() const
{
return mState.mFormat.info->redBits;
}
GLuint Renderbuffer::getGreenSize() const
{
return mState.mFormat.info->greenBits;
}
GLuint Renderbuffer::getBlueSize() const
{
return mState.mFormat.info->blueBits;
}
GLuint Renderbuffer::getAlphaSize() const
{
return mState.mFormat.info->alphaBits;
}
GLuint Renderbuffer::getDepthSize() const
{
return mState.mFormat.info->depthBits;
}
GLuint Renderbuffer::getStencilSize() const
{
return mState.mFormat.info->stencilBits;
}
const RenderbufferState &Renderbuffer::getState() const
{
return mState;
}
GLint Renderbuffer::getMemorySize() const
{
GLint implSize = mImplementation->getMemorySize();
if (implSize > 0)
{
return implSize;
}
// Assume allocated size is around width * height * samples * pixelBytes
angle::CheckedNumeric<GLint> size = 1;
size *= mState.mFormat.info->pixelBytes;
size *= mState.mWidth;
size *= mState.mHeight;
size *= std::max(mState.mSamples, 1);
return size.ValueOrDefault(std::numeric_limits<GLint>::max());
}
void Renderbuffer::onAttach(const Context *context, rx::Serial framebufferSerial)
{
addRef();
}
void Renderbuffer::onDetach(const Context *context, rx::Serial framebufferSerial)
{
release(context);
}
GLuint Renderbuffer::getId() const
{
return id().value;
}
Extents Renderbuffer::getAttachmentSize(const gl::ImageIndex & /*imageIndex*/) const
{
return Extents(mState.mWidth, mState.mHeight, 1);
}
Format Renderbuffer::getAttachmentFormat(GLenum /*binding*/,
const ImageIndex & /*imageIndex*/) const
{
return getFormat();
}
GLsizei Renderbuffer::getAttachmentSamples(const ImageIndex & /*imageIndex*/) const
{
return getSamples();
}
bool Renderbuffer::isRenderable(const Context *context,
GLenum binding,
const ImageIndex &imageIndex) const
{
if (isEGLImageTarget())
{
return ImageSibling::isRenderable(context, binding, imageIndex);
}
return getFormat().info->renderbufferSupport(context->getClientVersion(),
context->getExtensions());
}
InitState Renderbuffer::initState(const gl::ImageIndex & /*imageIndex*/) const
{
if (isEGLImageTarget())
{
return sourceEGLImageInitState();
}
return mState.mInitState;
}
void Renderbuffer::setInitState(const gl::ImageIndex & /*imageIndex*/, InitState initState)
{
if (isEGLImageTarget())
{
setSourceEGLImageInitState(initState);
}
else
{
mState.mInitState = initState;
}
}
rx::FramebufferAttachmentObjectImpl *Renderbuffer::getAttachmentImpl() const
{
return mImplementation.get();
}
GLenum Renderbuffer::getImplementationColorReadFormat(const Context *context) const
{
return mImplementation->getColorReadFormat(context);
}
GLenum Renderbuffer::getImplementationColorReadType(const Context *context) const
{
return mImplementation->getColorReadType(context);
}
angle::Result Renderbuffer::getRenderbufferImage(const Context *context,
const PixelPackState &packState,
Buffer *packBuffer,
GLenum format,
GLenum type,
void *pixels) const
{
return mImplementation->getRenderbufferImage(context, packState, packBuffer, format, type,
pixels);
}
void Renderbuffer::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
{
ASSERT(message == angle::SubjectMessage::SubjectChanged);
onStateChange(angle::SubjectMessage::ContentsChanged);
}
} // namespace gl