// // 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 releaseImage; (void)orphanImages(context, &releaseImage); if (mImplementation) { mImplementation->onDestroy(context); } } Renderbuffer::~Renderbuffer() {} angle::Result Renderbuffer::setLabel(const Context *context, const std::string &label) { mLabel = label; if (mImplementation) { return mImplementation->onLabelUpdate(context); } return angle::Result::Continue; } const std::string &Renderbuffer::getLabel() const { return mLabel; } angle::Result Renderbuffer::setStorage(const Context *context, GLenum internalformat, GLsizei width, GLsizei height) { egl::RefCountObjectReleaser 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 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 releaseImage; ANGLE_TRY(orphanImages(context, &releaseImage)); ANGLE_TRY(mImplementation->setStorageEGLImageTarget(context, image)); setTargetImage(context, image); mState.update(static_cast(image->getWidth()), static_cast(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 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::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(GLenum /*binding*/, const gl::ImageIndex & /*imageIndex*/) const { if (isEGLImageTarget()) { return sourceEGLImageInitState(); } return mState.mInitState; } void Renderbuffer::setInitState(GLenum /*binding*/, 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