/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "src/gpu/ganesh/gl/GrGLAttachment.h"

#include "include/core/SkTraceMemoryDump.h"
#include "src/gpu/ganesh/gl/GrGLGpu.h"

#define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X)

#define GL_ALLOC_CALL(call)                                   \
    [&] {                                                     \
        if (gpu->glCaps().skipErrorChecks()) {               \
            GR_GL_CALL(gpu->glInterface(), call);            \
            return static_cast<GrGLenum>(GR_GL_NO_ERROR);     \
        } else {                                              \
            gpu->clearErrorsAndCheckForOOM();                \
            GR_GL_CALL_NOERRCHECK(gpu->glInterface(), call); \
            return gpu->getErrorAndCheckForOOM();            \
        }                                                     \
    }()

static bool renderbuffer_storage_msaa(GrGLGpu* gpu,
                                      int sampleCount,
                                      GrGLenum format,
                                      int width,
                                      int height) {
    SkASSERT(GrGLCaps::kNone_MSFBOType != gpu->glCaps().msFBOType());
    GrGLenum error;
    switch (gpu->glCaps().msFBOType()) {
        case GrGLCaps::kStandard_MSFBOType:
            error = GL_ALLOC_CALL(RenderbufferStorageMultisample(
                    GR_GL_RENDERBUFFER, sampleCount, format, width, height));
            break;
        case GrGLCaps::kES_Apple_MSFBOType:
            error = GL_ALLOC_CALL(RenderbufferStorageMultisampleES2APPLE(
                    GR_GL_RENDERBUFFER, sampleCount, format, width, height));
            break;
        case GrGLCaps::kES_EXT_MsToTexture_MSFBOType:
        case GrGLCaps::kES_IMG_MsToTexture_MSFBOType:
            error = GL_ALLOC_CALL(RenderbufferStorageMultisampleES2EXT(
                    GR_GL_RENDERBUFFER, sampleCount, format, width, height));
            break;
        case GrGLCaps::kNone_MSFBOType:
            SkUNREACHABLE;
            break;
    }
    return error == GR_GL_NO_ERROR;
}

sk_sp<GrGLAttachment> GrGLAttachment::MakeStencil(GrGLGpu* gpu,
                                                  SkISize dimensions,
                                                  int sampleCnt,
                                                  GrGLFormat format) {
    GrGLuint rbID = 0;

    GL_CALL(GenRenderbuffers(1, &rbID));
    if (!rbID) {
        return nullptr;
    }
    GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, rbID));
    GrGLenum glFmt = GrGLFormatToEnum(format);
    // we do this "if" so that we don't call the multisample
    // version on a GL that doesn't have an MSAA extension.
    if (sampleCnt > 1) {
        if (!renderbuffer_storage_msaa(gpu, sampleCnt, glFmt, dimensions.width(),
                                       dimensions.height())) {
            GL_CALL(DeleteRenderbuffers(1, &rbID));
            return nullptr;
        }
    } else {
        GrGLenum error = GL_ALLOC_CALL(RenderbufferStorage(
                GR_GL_RENDERBUFFER, glFmt, dimensions.width(), dimensions.height()));
        if (error != GR_GL_NO_ERROR) {
            GL_CALL(DeleteRenderbuffers(1, &rbID));
            return nullptr;
        }
    }

    return sk_sp<GrGLAttachment>(new GrGLAttachment(gpu,
                                                    rbID,
                                                    dimensions,
                                                    GrAttachment::UsageFlags::kStencilAttachment,
                                                    sampleCnt,
                                                    format,
                                                    /*label=*/"GLAttachmentMakeStencil"));
}

sk_sp<GrGLAttachment> GrGLAttachment::MakeMSAA(GrGLGpu* gpu,
                                               SkISize dimensions,
                                               int sampleCnt,
                                               GrGLFormat format) {
    GrGLuint rbID = 0;

    GL_CALL(GenRenderbuffers(1, &rbID));
    if (!rbID) {
        return nullptr;
    }
    GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, rbID));
    GrGLenum glFmt = gpu->glCaps().getRenderbufferInternalFormat(format);
    if (!renderbuffer_storage_msaa(
            gpu, sampleCnt, glFmt, dimensions.width(), dimensions.height())) {
        GL_CALL(DeleteRenderbuffers(1, &rbID));
        return nullptr;
    }

    return sk_sp<GrGLAttachment>(new GrGLAttachment(gpu,
                                                    rbID,
                                                    dimensions,
                                                    GrAttachment::UsageFlags::kColorAttachment,
                                                    sampleCnt,
                                                    format,
                                                    /*label=*/"GLAttachmentMakeMSAA"));
}


void GrGLAttachment::onRelease() {
    if (0 != fRenderbufferID) {
        GrGLGpu* gpuGL = (GrGLGpu*)this->getGpu();
        const GrGLInterface* gl = gpuGL->glInterface();
        GR_GL_CALL(gl, DeleteRenderbuffers(1, &fRenderbufferID));
        fRenderbufferID = 0;
    }

    INHERITED::onRelease();
}

void GrGLAttachment::onAbandon() {
    fRenderbufferID = 0;

    INHERITED::onAbandon();
}

GrBackendFormat GrGLAttachment::backendFormat() const {
    return GrBackendFormat::MakeGL(GrGLFormatToEnum(fFormat), GR_GL_TEXTURE_NONE);
}

void GrGLAttachment::setMemoryBacking(SkTraceMemoryDump* traceMemoryDump,
                                      const SkString& dumpName) const {
    SkString renderbuffer_id;
    renderbuffer_id.appendU32(this->renderbufferID());
    traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_renderbuffer", renderbuffer_id.c_str());
}

void GrGLAttachment::onSetLabel() {
    SkASSERT(fRenderbufferID);
    if (!this->getLabel().empty()) {
        const std::string label = "_Skia_" + this->getLabel();
        GrGLGpu* glGpu = static_cast<GrGLGpu*>(this->getGpu());
        if (glGpu->glCaps().debugSupport()) {
            GR_GL_CALL(glGpu->glInterface(),
                       ObjectLabel(GR_GL_TEXTURE, fRenderbufferID, -1, label.c_str()));
        }
    }
}
