/*
* Copyright (C) 2016 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.
*/
#pragma once

#include <assert.h>
#include <GLES/gl.h>
#include <memory>

enum class NamedObjectType : short {
    NULLTYPE,
    VERTEXBUFFER,
    TEXTURE,
    RENDERBUFFER,
    FRAMEBUFFER,
    SHADER_OR_PROGRAM,
    SAMPLER,
    QUERY,
    VERTEX_ARRAY_OBJECT,
    TRANSFORM_FEEDBACK,
    NUM_OBJECT_TYPES  // Must be last
};

enum class ShaderProgramType : short {
    PROGRAM,
    VERTEX_SHADER,
    FRAGMENT_SHADER,
    COMPUTE_SHADER,
};

//
// Class GenNameInfo - this class contains the type of an GL object to be
//                     generated. It also contains shader type when generating
//                     shader object.
//                     It is used by GlobalNameSpace::genName.
//                     When generating an object that is not shader or program,
//                     a NamedObjectType parameter should be passed to the
//                     constructor. When generating shader / program object, the
//                     ShaderProgramType should be passed to the constructor.
// Example:
//          GlobalNameSpace globalNameSpace;
//          GenNameInfo genTexture(NamedObjectType::TEXTURE);
//          unsigned int texID = globalNameSpace.genName(genTexture);
//          GenNameInfo genShader(ShaderProgramType::FRAGMENT_SHADER);
//          unsigned int shaderID = globalNameSpace.genName(genShader);

struct GenNameInfo {
    NamedObjectType m_type = (NamedObjectType)0;
    // only used for NamedObjectType::SHADER_OR_PROGRAM
    ShaderProgramType m_shaderProgramType = (ShaderProgramType)0;
    // only used for NamedObjectType::SHADER_OR_PROGRAM, so far.
    GLuint m_existingGlobal = 0;

    GenNameInfo() = delete;
    // constructor for generating non-shader object
    explicit GenNameInfo(NamedObjectType type) : m_type(type) {
        assert(type != NamedObjectType::SHADER_OR_PROGRAM);
    }
    // constructor for generating shader object
    explicit GenNameInfo(ShaderProgramType shaderProgramType,
                         GLuint existingGlobal = 0) :
        m_type(NamedObjectType::SHADER_OR_PROGRAM),
        m_shaderProgramType(shaderProgramType),
        m_existingGlobal(existingGlobal) {}
};


typedef unsigned long long ObjectLocalName;

class GlobalNameSpace;

// NamedObject is used to manage GPU names.
// It generates / releases GPU names.
// NamedObject is expected to be encapsulated in a shared pointer when used (see
// NamedObjectPtr). The main purpose to use smart pointers is to have reference
// counters for texture objects, which are frequently shared across contexts and
// share groups when used in EGLImages. The specification of EGLImage says:
//
//    Once an EGLImage is created from an EGLImage source, the memory associated
//    with the EGLImage source will remain allocated (and all EGLImage siblings
//    in all client API contexts will be useable) as long as either of the
//    following conditions is true:
//      A)  Any EGLImage siblings exist in any client API context
//      B)  The EGLImage object exists inside EGL
// Reference: 2.5.2  Lifetime and Usage of EGLImages in
// https://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_image_base.txt
//
// In our situation, "the memory associated with the EGLImage source" means the
// textures. Thus a shared pointer is needed.

class NamedObject {
public:
    NamedObject(GenNameInfo genNameInfo,
                GlobalNameSpace *globalNameSpace);
    ~NamedObject();
    unsigned int getGlobalName() const {return m_globalName;}
private:
    // m_globalName is the name generated by GPU
    unsigned int m_globalName = 0;
    NamedObjectType m_type;
    GlobalNameSpace *m_globalNameSpace;
};

typedef std::shared_ptr<NamedObject> NamedObjectPtr;
