//
// Copyright 2020 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.
//

// FramebufferObjectTest.cpp: Tests basic usage of OES_framebuffer_object extension.

#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"

using namespace angle;

class FramebufferObjectTest : public ANGLETest
{
  protected:
    FramebufferObjectTest()
    {
        setWindowWidth(32);
        setWindowHeight(32);
        setConfigRedBits(8);
        setConfigGreenBits(8);
        setConfigBlueBits(8);
        setConfigAlphaBits(8);
        setConfigDepthBits(24);
    }

    void testSetUp() override
    {
        mTexture.reset(new GLTexture());
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, mTexture->get());
    }

    void testTearDown() override { mTexture.reset(); }

    std::unique_ptr<GLTexture> mTexture;
};

// Checks that framebuffer object can be used without GL errors.
TEST_P(FramebufferObjectTest, FramebufferObject)
{
    GLuint fboId;
    GLint params;

    glGenFramebuffersOES(1, &fboId);
    EXPECT_GL_NO_ERROR();
    glIsFramebufferOES(fboId);
    EXPECT_GL_NO_ERROR();
    glBindFramebufferOES(GL_FRAMEBUFFER, fboId);
    EXPECT_GL_NO_ERROR();

    glCheckFramebufferStatusOES(GL_FRAMEBUFFER);
    EXPECT_GL_NO_ERROR();
    glGetFramebufferAttachmentParameterivOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                             GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &params);
    EXPECT_GL_NO_ERROR();

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glDeleteFramebuffersOES(1, &fboId);
    EXPECT_GL_NO_ERROR();
}

// Checks that texture object can be bound for framebuffer object.
TEST_P(FramebufferObjectTest, TextureObject)
{
    GLuint fboId;

    glGenFramebuffers(1, &fboId);
    glBindFramebuffer(GL_FRAMEBUFFER, fboId);
    glFramebufferTexture2DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture->get(),
                              0);
    EXPECT_GL_NO_ERROR();

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glDeleteFramebuffers(1, &fboId);
}

// Checks that renderbuffer object can be used and can be bound for framebuffer object.
TEST_P(FramebufferObjectTest, RenderbufferObject)
{
    GLuint fboId;
    GLuint rboId;
    GLint params;

    glGenFramebuffers(1, &fboId);
    glBindFramebuffer(GL_FRAMEBUFFER, fboId);

    glGenRenderbuffersOES(1, &rboId);
    EXPECT_GL_NO_ERROR();
    glIsRenderbufferOES(rboId);
    EXPECT_GL_NO_ERROR();
    glBindRenderbufferOES(GL_RENDERBUFFER, rboId);
    EXPECT_GL_NO_ERROR();
    glRenderbufferStorageOES(GL_RENDERBUFFER, GL_RGBA8, 32, 32);
    EXPECT_GL_NO_ERROR();

    glFramebufferRenderbufferOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboId);
    EXPECT_GL_NO_ERROR();
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &params);
    EXPECT_GL_NO_ERROR();

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glDeleteFramebuffers(1, &fboId);
    glDeleteRenderbuffersOES(1, &rboId);
    EXPECT_GL_NO_ERROR();
}

// Checks that generateMipmap can be called without GL errors.
TEST_P(FramebufferObjectTest, GenerateMipmap)
{
    constexpr uint32_t kSize = 32;
    std::vector<unsigned char> pixelData(kSize * kSize * 4, 0);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixelData.data());

    glGenerateMipmapOES(GL_TEXTURE_2D);
    EXPECT_GL_NO_ERROR();
}

ANGLE_INSTANTIATE_TEST_ES1(FramebufferObjectTest);