//
// 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.h: Defines the renderer-agnostic container class gl::Renderbuffer.
// Implements GL renderbuffer objects and related functionality.
// [OpenGL ES 2.0.24] section 4.4.3 page 108.

#ifndef LIBANGLE_RENDERBUFFER_H_
#define LIBANGLE_RENDERBUFFER_H_

#include "angle_gl.h"
#include "common/angleutils.h"
#include "libANGLE/Debug.h"
#include "libANGLE/Error.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/Image.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/RenderbufferImpl.h"

namespace rx
{
class GLImplFactory;
}  // namespace rx

namespace gl
{
// A GL renderbuffer object is usually used as a depth or stencil buffer attachment
// for a framebuffer object. The renderbuffer itself is a distinct GL object, see
// FramebufferAttachment and Framebuffer for how they are applied to an FBO via an
// attachment point.

class RenderbufferState final : angle::NonCopyable
{
  public:
    RenderbufferState();
    ~RenderbufferState();

    GLsizei getWidth() const;
    GLsizei getHeight() const;
    const Format &getFormat() const;
    GLsizei getSamples() const;
    MultisamplingMode getMultisamplingMode() const;
    InitState getInitState() const;
    void setProtectedContent(bool hasProtectedContent);

    const egl::ImageSourceAttributes &getEGLImageSourceAttributes() const
    {
        return mEGLImageSourceAttributes;
    }

    SourceImageIndex toSourceIndex(const OwnImageIndex &index) const
    {
        return mEGLImageSourceAttributes.toSourceIndex(index);
    }
    SourceLevel toSourceLevel(OwnLevel level) const
    {
        return mEGLImageSourceAttributes.toSourceLevel(level);
    }
    SourceLayer toSourceLayer(OwnLayer layer) const
    {
        return mEGLImageSourceAttributes.toSourceLayer(layer);
    }

  private:
    friend class Renderbuffer;

    void update(GLsizei width,
                GLsizei height,
                const Format &format,
                GLsizei samples,
                MultisamplingMode multisamplingMode,
                InitState initState);

    GLsizei mWidth;
    GLsizei mHeight;
    Format mFormat;
    GLsizei mSamples;
    MultisamplingMode mMultisamplingMode;
    bool mHasProtectedContent;

    // For robust resource init.
    InitState mInitState;

    // |mEGLImageSourceAttributes.type| is only valid if this texture is an "EGLImage target" and
    // the associated EGL Image was originally sourced from an OpenGL texture.  Such EGL Images can
    // be a slice of the underlying resource.  The level and layer offset are used to track the
    // location of the slice.
    egl::ImageSourceAttributes mEGLImageSourceAttributes;
};

class Renderbuffer final : public RefCountObject<RenderbufferID>,
                           public egl::ImageSibling,
                           public LabeledObject
{
  public:
    Renderbuffer(rx::GLImplFactory *implFactory, RenderbufferID id);
    ~Renderbuffer() override;

    void onDestroy(const Context *context) override;

    angle::Result setLabel(const Context *context, const std::string &label) override;
    const std::string &getLabel() const override;

    angle::Result setStorage(const Context *context,
                             GLenum internalformat,
                             GLsizei width,
                             GLsizei height);
    angle::Result setStorageMultisample(const Context *context,
                                        GLsizei samplesIn,
                                        GLenum internalformat,
                                        GLsizei width,
                                        GLsizei height,
                                        MultisamplingMode mode);
    angle::Result setStorageEGLImageTarget(const Context *context, egl::Image *imageTarget);

    angle::Result copyRenderbufferSubData(Context *context,
                                          const gl::Renderbuffer *srcBuffer,
                                          GLint srcX,
                                          GLint srcY,
                                          GLint dstX,
                                          GLint dstY,
                                          GLsizei srcWidth,
                                          GLsizei srcHeight);

    angle::Result copyTextureSubData(Context *context,
                                     const gl::Texture *srcTexture,
                                     GLint srcLevel,
                                     GLint srcX,
                                     GLint srcY,
                                     GLint srcZ,
                                     GLint dstX,
                                     GLint dstY,
                                     GLsizei srcWidth,
                                     GLsizei srcHeight);

    rx::RenderbufferImpl *getImplementation() const;

    GLsizei getWidth() const;
    GLsizei getHeight() const;
    const Format &getFormat() const;
    GLsizei getSamples() const;
    MultisamplingMode getMultisamplingMode() const;
    GLuint getRedSize() const;
    GLuint getGreenSize() const;
    GLuint getBlueSize() const;
    GLuint getAlphaSize() const;
    GLuint getDepthSize() const;
    GLuint getStencilSize() const;
    const RenderbufferState &getState() const;

    GLint getMemorySize() const;

    // FramebufferAttachmentObject Impl
    Extents getAttachmentSize(const ImageIndex &imageIndex) const override;
    Format getAttachmentFormat(GLenum binding, const ImageIndex &imageIndex) const override;
    GLsizei getAttachmentSamples(const ImageIndex &imageIndex) const override;
    bool isRenderable(const Context *context,
                      GLenum binding,
                      const ImageIndex &imageIndex) const override;
    bool isEGLImageSource() const;

    void onAttach(const Context *context, rx::UniqueSerial framebufferSerial) override;
    void onDetach(const Context *context, rx::UniqueSerial framebufferSerial) override;
    GLuint getId() const override;

    InitState initState(GLenum binding, const ImageIndex &imageIndex) const override;
    void setInitState(GLenum binding, const ImageIndex &imageIndex, InitState initState) override;

    GLenum getImplementationColorReadFormat(const Context *context) const;
    GLenum getImplementationColorReadType(const Context *context) const;

    // We pass the pack buffer and state explicitly so they can be overridden during capture.
    angle::Result getRenderbufferImage(const Context *context,
                                       const PixelPackState &packState,
                                       Buffer *packBuffer,
                                       GLenum format,
                                       GLenum type,
                                       void *pixels) const;

  private:
    // ObserverInterface implementation.
    void onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message) override;

    angle::Result orphanImages(const gl::Context *context,
                               egl::RefCountObjectReleaser<egl::Image> *outReleaseImage);

    rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override;

    RenderbufferState mState;
    std::unique_ptr<rx::RenderbufferImpl> mImplementation;

    std::string mLabel;
    angle::ObserverBinding mImplObserverBinding;
};

}  // namespace gl

#endif  // LIBANGLE_RENDERBUFFER_H_
