// Copyright (C) 2018 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "GLSnapshotTestStateUtils.h"

#include "GLSnapshotTesting.h"
#include "apigen-codec-common/glUtils.h"

#include <gtest/gtest.h>

#include <GLES2/gl2.h>
#include <GLES3/gl31.h>

namespace gfxstream {
namespace gl {

GLuint createBuffer(const GLESv2Dispatch* gl, GlBufferData data) {
    // We bind to GL_ARRAY_BUFFER in order to set up buffer data,
    // so let's hold on to what the old binding was so we can restore it
    GLuint currentArrayBuffer;
    gl->glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&currentArrayBuffer);
    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());

    GLuint name;
    gl->glGenBuffers(1, &name);
    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());

    gl->glBindBuffer(GL_ARRAY_BUFFER, name);
    gl->glBufferData(GL_ARRAY_BUFFER, data.size, data.bytes, data.usage);

    // Restore the old binding
    gl->glBindBuffer(GL_ARRAY_BUFFER, currentArrayBuffer);
    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
    return name;
};

GLuint loadAndCompileShader(const GLESv2Dispatch* gl,
                            GLenum shaderType,
                            const char* src) {
    GLuint shader = gl->glCreateShader(shaderType);
    gl->glShaderSource(shader, 1, (const GLchar* const*)&src, nullptr);
    gl->glCompileShader(shader);

    GLint compileStatus;
    gl->glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
    EXPECT_EQ(GL_TRUE, compileStatus);

    if (compileStatus != GL_TRUE) {
        GLsizei infoLogLength;
        gl->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
        std::vector<char> infoLog;
        infoLog.resize(infoLogLength);
        gl->glGetShaderInfoLog(shader, infoLogLength, nullptr, &infoLog[0]);
        fprintf(stderr, "%s: fail to compile. infolog %s\n", __func__,
                &infoLog[0]);
    }

    return shader;
}

std::vector<GLubyte> getTextureImageData(const GLESv2Dispatch* gl,
                                         GLuint texture,
                                         GLenum target,
                                         GLint level,
                                         GLsizei width,
                                         GLsizei height,
                                         GLenum format,
                                         GLenum type) {
    std::vector<GLubyte> out = {};
    out.resize(width * height *
               glUtilsPixelBitSize(GL_RGBA /* format */,
                                   GL_UNSIGNED_BYTE /* type */) / 8);

    // switch to auxiliary framebuffer
    GLint oldFramebuffer;
    gl->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFramebuffer);

    GLuint auxFramebuffer;
    gl->glGenFramebuffers(1, &auxFramebuffer);
    gl->glBindFramebuffer(GL_FRAMEBUFFER, auxFramebuffer);
    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());

    gl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target,
                               texture, level);
    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
    gl->glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
                     out.data());  // TODO(benzene): flexible format/type?
                                   // seems like RGBA/UNSIGNED_BYTE is the only
                                   // guaranteed supported format+type
    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());

    // restore old framebuffer
    gl->glBindFramebuffer(GL_FRAMEBUFFER, oldFramebuffer);
    gl->glDeleteFramebuffers(1, &auxFramebuffer);
    EXPECT_EQ(GL_NO_ERROR, gl->glGetError());

    return out;
}

}  // namespace gl
}  // namespace gfxstream
