/*
 * Copyright (C) 2010 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 "GLExtensions.h"

#include <string>
#include <unordered_set>

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

ANDROID_SINGLETON_STATIC_INSTANCE(android::renderengine::gl::GLExtensions)

namespace android {
namespace renderengine {
namespace gl {

namespace {

class ExtensionSet {
public:
    ExtensionSet(const char* extensions) {
        char const* curr = extensions;
        char const* head = curr;
        do {
            head = strchr(curr, ' ');
            size_t len = head ? head - curr : strlen(curr);
            if (len > 0) {
                mExtensions.emplace(curr, len);
            }
            curr = head + 1;
        } while (head);
    }

    bool hasExtension(const char* extension) const { return mExtensions.count(extension) > 0; }

private:
    std::unordered_set<std::string> mExtensions;
};

} // anonymous namespace

void GLExtensions::initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer,
                                     GLubyte const* version, GLubyte const* extensions) {
    mVendor = (char const*)vendor;
    mRenderer = (char const*)renderer;
    mVersion = (char const*)version;
    mExtensions = (char const*)extensions;

    ExtensionSet extensionSet(mExtensions.c_str());
    if (extensionSet.hasExtension("GL_EXT_protected_textures")) {
        mHasProtectedTexture = true;
    }
}

char const* GLExtensions::getVendor() const {
    return mVendor.c_str();
}

char const* GLExtensions::getRenderer() const {
    return mRenderer.c_str();
}

char const* GLExtensions::getVersion() const {
    return mVersion.c_str();
}

char const* GLExtensions::getExtensions() const {
    return mExtensions.c_str();
}

void GLExtensions::initWithEGLStrings(char const* eglVersion, char const* eglExtensions) {
    mEGLVersion = eglVersion;
    mEGLExtensions = eglExtensions;

    ExtensionSet extensionSet(eglExtensions);

    // EGL_ANDROIDX_no_config_context is an experimental extension with no
    // written specification. It will be replaced by something more formal.
    // SurfaceFlinger is using it to allow a single EGLContext to render to
    // both a 16-bit primary display framebuffer and a 32-bit virtual display
    // framebuffer.
    //
    // EGL_KHR_no_config_context is official extension to allow creating a
    // context that works with any surface of a display.
    if (extensionSet.hasExtension("EGL_ANDROIDX_no_config_context") ||
        extensionSet.hasExtension("EGL_KHR_no_config_context")) {
        mHasNoConfigContext = true;
    }

    if (extensionSet.hasExtension("EGL_ANDROID_native_fence_sync")) {
        mHasNativeFenceSync = true;
    }
    if (extensionSet.hasExtension("EGL_KHR_fence_sync")) {
        mHasFenceSync = true;
    }
    if (extensionSet.hasExtension("EGL_KHR_wait_sync")) {
        mHasWaitSync = true;
    }
    if (extensionSet.hasExtension("EGL_EXT_protected_content")) {
        mHasProtectedContent = true;
    }
    if (extensionSet.hasExtension("EGL_IMG_context_priority")) {
        mHasContextPriority = true;
    }
    if (extensionSet.hasExtension("EGL_KHR_surfaceless_context")) {
        mHasSurfacelessContext = true;
    }
}

char const* GLExtensions::getEGLVersion() const {
    return mEGLVersion.c_str();
}

char const* GLExtensions::getEGLExtensions() const {
    return mEGLExtensions.c_str();
}

} // namespace gl
} // namespace renderengine
} // namespace android
