| // |
| // 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; |
| } // namespace |
| |
| // RenderbufferState implementation. |
| RenderbufferState::RenderbufferState() |
| : mWidth(0), mHeight(0), mFormat(GL_RGBA4), mSamples(0), mInitState(InitState::MayNeedInit) |
| {} |
| |
| 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; |
| } |
| |
| void RenderbufferState::update(GLsizei width, |
| GLsizei height, |
| const Format &format, |
| GLsizei samples, |
| InitState initState) |
| { |
| mWidth = static_cast<GLsizei>(width); |
| mHeight = static_cast<GLsizei>(height); |
| mFormat = format; |
| mSamples = samples; |
| mInitState = InitState::MayNeedInit; |
| } |
| |
| // 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) |
| { |
| (void)(orphanImages(context)); |
| |
| 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, |
| size_t width, |
| size_t height) |
| { |
| ANGLE_TRY(orphanImages(context)); |
| ANGLE_TRY(mImplementation->setStorage(context, internalformat, width, height)); |
| |
| mState.update(static_cast<GLsizei>(width), static_cast<GLsizei>(height), Format(internalformat), |
| 0, InitState::MayNeedInit); |
| onStateChange(angle::SubjectMessage::SubjectChanged); |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result Renderbuffer::setStorageMultisample(const Context *context, |
| size_t samples, |
| GLenum internalformat, |
| size_t width, |
| size_t height) |
| { |
| ANGLE_TRY(orphanImages(context)); |
| |
| // Potentially adjust "samples" to a supported value |
| const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); |
| samples = formatCaps.getNearestSamples(static_cast<GLuint>(samples)); |
| |
| ANGLE_TRY( |
| mImplementation->setStorageMultisample(context, samples, internalformat, width, height)); |
| |
| mState.update(static_cast<GLsizei>(width), static_cast<GLsizei>(height), Format(internalformat), |
| static_cast<GLsizei>(samples), InitState::MayNeedInit); |
| onStateChange(angle::SubjectMessage::SubjectChanged); |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result Renderbuffer::setStorageEGLImageTarget(const Context *context, egl::Image *image) |
| { |
| ANGLE_TRY(orphanImages(context)); |
| 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, image->sourceInitState()); |
| onStateChange(angle::SubjectMessage::SubjectChanged); |
| |
| 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.mSamples; |
| } |
| |
| 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; |
| } |
| |
| 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) |
| { |
| addRef(); |
| } |
| |
| void Renderbuffer::onDetach(const Context *context) |
| { |
| 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 |