/*
 * 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 "VkInteropFunctorDrawable.h"
#include <private/hwui/DrawGlInfo.h>

#include <utils/Color.h>
#include <utils/Trace.h>
#include <utils/TraceUtils.h>
#include <thread>
#include "renderthread/EglManager.h"
#include "thread/ThreadBase.h"
#include "utils/TimeUtils.h"

#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES3/gl3.h>

#include <utils/GLUtils.h>

namespace android {
namespace uirenderer {
namespace skiapipeline {

static renderthread::EglManager sEglManager;

// ScopedDrawRequest makes sure a GL thread is started and EGL context is initialized on it.
class ScopedDrawRequest {
public:
    ScopedDrawRequest() { beginDraw(); }

private:
    void beginDraw() {
        if (!sEglManager.hasEglContext()) {
            sEglManager.initialize();
        }
    }
};

void VkInteropFunctorDrawable::vkInvokeFunctor(Functor* functor) {
    ScopedDrawRequest _drawRequest{};
    EGLDisplay display = sEglManager.eglDisplay();
    DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
    if (display != EGL_NO_DISPLAY) {
        mode = DrawGlInfo::kModeProcess;
    }
    (*functor)(mode, nullptr);
}

#define FENCE_TIMEOUT 2000000000

void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
    ATRACE_CALL();

    if (canvas->getGrContext() == nullptr) {
        SkDEBUGF(("Attempting to draw VkInteropFunctor into an unsupported surface"));
        return;
    }

    ScopedDrawRequest _drawRequest{};

    SkImageInfo surfaceInfo = canvas->imageInfo();

    if (!mFrameBuffer.get() || mFBInfo != surfaceInfo) {
        // Buffer will be used as an OpenGL ES render target.
        mFrameBuffer = new GraphicBuffer(
                // TODO: try to reduce the size of the buffer: possibly by using clip bounds.
                static_cast<uint32_t>(surfaceInfo.width()),
                static_cast<uint32_t>(surfaceInfo.height()),
                ColorTypeToPixelFormat(surfaceInfo.colorType()),
                GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
                        GraphicBuffer::USAGE_SW_READ_NEVER | GraphicBuffer::USAGE_HW_RENDER,
                std::string("VkInteropFunctorDrawable::onDraw pid [") + std::to_string(getpid()) +
                        "]");
        status_t error = mFrameBuffer->initCheck();
        if (error < 0) {
            ALOGW("VkInteropFunctorDrawable::onDraw() failed in GraphicBuffer.create()");
            return;
        }

        mFBInfo = surfaceInfo;
    }

    // TODO: Synchronization is needed on mFrameBuffer to guarantee that the previous Vulkan
    // TODO: draw command has completed.
    // TODO: A simple but inefficient way is to flush and issue a QueueWaitIdle call. See
    // TODO: GrVkGpu::destroyResources() for example.
    {
        ATRACE_FORMAT("WebViewDraw_%dx%d", mFBInfo.width(), mFBInfo.height());
        EGLDisplay display = sEglManager.eglDisplay();
        LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
                            uirenderer::renderthread::EglManager::eglErrorString());
        // We use an EGLImage to access the content of the GraphicBuffer
        // The EGL image is later bound to a 2D texture
        EGLClientBuffer clientBuffer = (EGLClientBuffer)mFrameBuffer->getNativeBuffer();
        AutoEglImage autoImage(display, clientBuffer);
        if (autoImage.image == EGL_NO_IMAGE_KHR) {
            ALOGW("Could not create EGL image, err =%s",
                  uirenderer::renderthread::EglManager::eglErrorString());
            return;
        }

        AutoSkiaGlTexture glTexture;
        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
        GL_CHECKPOINT(MODERATE);

        glBindTexture(GL_TEXTURE_2D, 0);

        DrawGlInfo info;
        SkM44 mat4(canvas->experimental_getLocalToDevice());
        SkIRect clipBounds = canvas->getDeviceClipBounds();

        info.clipLeft = clipBounds.fLeft;
        info.clipTop = clipBounds.fTop;
        info.clipRight = clipBounds.fRight;
        info.clipBottom = clipBounds.fBottom;
        info.isLayer = true;
        info.width = mFBInfo.width();
        info.height = mFBInfo.height();
        mat4.getColMajor(&info.transform[0]);
        info.color_space_ptr = canvas->imageInfo().colorSpace();

        glViewport(0, 0, info.width, info.height);

        AutoGLFramebuffer glFb;
        // Bind texture to the frame buffer.
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
                               glTexture.mTexture, 0);
        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
            ALOGE("Failed framebuffer check for created target buffer: %s",
                  GLUtils::getGLFramebufferError());
            return;
        }

        glDisable(GL_STENCIL_TEST);
        glDisable(GL_SCISSOR_TEST);
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        if (mAnyFunctor.index() == 0) {
            std::get<0>(mAnyFunctor).handle->drawGl(info);
        } else {
            (*(std::get<1>(mAnyFunctor).functor))(DrawGlInfo::kModeDraw, &info);
        }

        EGLSyncKHR glDrawFinishedFence =
                eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
        LOG_ALWAYS_FATAL_IF(glDrawFinishedFence == EGL_NO_SYNC_KHR,
                            "Could not create sync fence %#x", eglGetError());
        glFlush();
        // TODO: export EGLSyncKHR in file descr
        // TODO: import file desc in Vulkan Semaphore
        // TODO: instead block the GPU: probably by using external Vulkan semaphore.
        // Block the CPU until the glFlush finish.
        EGLint waitStatus = eglClientWaitSyncKHR(display, glDrawFinishedFence, 0, FENCE_TIMEOUT);
        LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
                            "Failed to wait for the fence %#x", eglGetError());
        eglDestroySyncKHR(display, glDrawFinishedFence);
    }

    SkPaint paint;
    paint.setBlendMode(SkBlendMode::kSrcOver);
    canvas->save();
    // The size of the image matches the size of the canvas. We've used the matrix already, while
    // drawing into the offscreen surface, so we need to reset it here.
    canvas->resetMatrix();

    auto functorImage = SkImage::MakeFromAHardwareBuffer(
            reinterpret_cast<AHardwareBuffer*>(mFrameBuffer.get()), kPremul_SkAlphaType,
            canvas->imageInfo().refColorSpace(), kBottomLeft_GrSurfaceOrigin);
    canvas->drawImage(functorImage, 0, 0, &paint);
    canvas->restore();
}

VkInteropFunctorDrawable::~VkInteropFunctorDrawable() {
    if (auto lp = std::get_if<LegacyFunctor>(&mAnyFunctor)) {
        if (lp->listener) {
            ScopedDrawRequest _drawRequest{};
            lp->listener->onGlFunctorReleased(lp->functor);
        }
    }
}

void VkInteropFunctorDrawable::syncFunctor(const WebViewSyncData& data) const {
    ScopedDrawRequest _drawRequest{};
    FunctorDrawable::syncFunctor(data);
}

}  // namespace skiapipeline
}  // namespace uirenderer
}  // namespace android
