// Copyright 2017 The Dawn Authors
//
// 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 "dawn_native/opengl/RenderPipelineGL.h"

#include "dawn_native/opengl/DeviceGL.h"
#include "dawn_native/opengl/Forward.h"
#include "dawn_native/opengl/PersistentPipelineStateGL.h"
#include "dawn_native/opengl/UtilsGL.h"

namespace dawn::native::opengl {

    namespace {

        GLenum GLPrimitiveTopology(wgpu::PrimitiveTopology primitiveTopology) {
            switch (primitiveTopology) {
                case wgpu::PrimitiveTopology::PointList:
                    return GL_POINTS;
                case wgpu::PrimitiveTopology::LineList:
                    return GL_LINES;
                case wgpu::PrimitiveTopology::LineStrip:
                    return GL_LINE_STRIP;
                case wgpu::PrimitiveTopology::TriangleList:
                    return GL_TRIANGLES;
                case wgpu::PrimitiveTopology::TriangleStrip:
                    return GL_TRIANGLE_STRIP;
            }
            UNREACHABLE();
        }

        void ApplyFrontFaceAndCulling(const OpenGLFunctions& gl,
                                      wgpu::FrontFace face,
                                      wgpu::CullMode mode) {
            // Note that we invert winding direction in OpenGL. Because Y axis is up in OpenGL,
            // which is different from WebGPU and other backends (Y axis is down).
            GLenum direction = (face == wgpu::FrontFace::CCW) ? GL_CW : GL_CCW;
            gl.FrontFace(direction);

            if (mode == wgpu::CullMode::None) {
                gl.Disable(GL_CULL_FACE);
            } else {
                gl.Enable(GL_CULL_FACE);

                GLenum cullMode = (mode == wgpu::CullMode::Front) ? GL_FRONT : GL_BACK;
                gl.CullFace(cullMode);
            }
        }

        GLenum GLBlendFactor(wgpu::BlendFactor factor, bool alpha) {
            switch (factor) {
                case wgpu::BlendFactor::Zero:
                    return GL_ZERO;
                case wgpu::BlendFactor::One:
                    return GL_ONE;
                case wgpu::BlendFactor::Src:
                    return GL_SRC_COLOR;
                case wgpu::BlendFactor::OneMinusSrc:
                    return GL_ONE_MINUS_SRC_COLOR;
                case wgpu::BlendFactor::SrcAlpha:
                    return GL_SRC_ALPHA;
                case wgpu::BlendFactor::OneMinusSrcAlpha:
                    return GL_ONE_MINUS_SRC_ALPHA;
                case wgpu::BlendFactor::Dst:
                    return GL_DST_COLOR;
                case wgpu::BlendFactor::OneMinusDst:
                    return GL_ONE_MINUS_DST_COLOR;
                case wgpu::BlendFactor::DstAlpha:
                    return GL_DST_ALPHA;
                case wgpu::BlendFactor::OneMinusDstAlpha:
                    return GL_ONE_MINUS_DST_ALPHA;
                case wgpu::BlendFactor::SrcAlphaSaturated:
                    return GL_SRC_ALPHA_SATURATE;
                case wgpu::BlendFactor::Constant:
                    return alpha ? GL_CONSTANT_ALPHA : GL_CONSTANT_COLOR;
                case wgpu::BlendFactor::OneMinusConstant:
                    return alpha ? GL_ONE_MINUS_CONSTANT_ALPHA : GL_ONE_MINUS_CONSTANT_COLOR;
            }
            UNREACHABLE();
        }

        GLenum GLBlendMode(wgpu::BlendOperation operation) {
            switch (operation) {
                case wgpu::BlendOperation::Add:
                    return GL_FUNC_ADD;
                case wgpu::BlendOperation::Subtract:
                    return GL_FUNC_SUBTRACT;
                case wgpu::BlendOperation::ReverseSubtract:
                    return GL_FUNC_REVERSE_SUBTRACT;
                case wgpu::BlendOperation::Min:
                    return GL_MIN;
                case wgpu::BlendOperation::Max:
                    return GL_MAX;
            }
            UNREACHABLE();
        }

        void ApplyColorState(const OpenGLFunctions& gl,
                             ColorAttachmentIndex attachment,
                             const ColorTargetState* state) {
            GLuint colorBuffer = static_cast<GLuint>(static_cast<uint8_t>(attachment));
            if (state->blend != nullptr) {
                gl.Enablei(GL_BLEND, colorBuffer);
                gl.BlendEquationSeparatei(colorBuffer, GLBlendMode(state->blend->color.operation),
                                          GLBlendMode(state->blend->alpha.operation));
                gl.BlendFuncSeparatei(colorBuffer,
                                      GLBlendFactor(state->blend->color.srcFactor, false),
                                      GLBlendFactor(state->blend->color.dstFactor, false),
                                      GLBlendFactor(state->blend->alpha.srcFactor, true),
                                      GLBlendFactor(state->blend->alpha.dstFactor, true));
            } else {
                gl.Disablei(GL_BLEND, colorBuffer);
            }
            gl.ColorMaski(colorBuffer, state->writeMask & wgpu::ColorWriteMask::Red,
                          state->writeMask & wgpu::ColorWriteMask::Green,
                          state->writeMask & wgpu::ColorWriteMask::Blue,
                          state->writeMask & wgpu::ColorWriteMask::Alpha);
        }

        void ApplyColorState(const OpenGLFunctions& gl, const ColorTargetState* state) {
            if (state->blend != nullptr) {
                gl.Enable(GL_BLEND);
                gl.BlendEquationSeparate(GLBlendMode(state->blend->color.operation),
                                         GLBlendMode(state->blend->alpha.operation));
                gl.BlendFuncSeparate(GLBlendFactor(state->blend->color.srcFactor, false),
                                     GLBlendFactor(state->blend->color.dstFactor, false),
                                     GLBlendFactor(state->blend->alpha.srcFactor, true),
                                     GLBlendFactor(state->blend->alpha.dstFactor, true));
            } else {
                gl.Disable(GL_BLEND);
            }
            gl.ColorMask(state->writeMask & wgpu::ColorWriteMask::Red,
                         state->writeMask & wgpu::ColorWriteMask::Green,
                         state->writeMask & wgpu::ColorWriteMask::Blue,
                         state->writeMask & wgpu::ColorWriteMask::Alpha);
        }

        bool Equal(const BlendComponent& lhs, const BlendComponent& rhs) {
            return lhs.operation == rhs.operation && lhs.srcFactor == rhs.srcFactor &&
                   lhs.dstFactor == rhs.dstFactor;
        }

        GLuint OpenGLStencilOperation(wgpu::StencilOperation stencilOperation) {
            switch (stencilOperation) {
                case wgpu::StencilOperation::Keep:
                    return GL_KEEP;
                case wgpu::StencilOperation::Zero:
                    return GL_ZERO;
                case wgpu::StencilOperation::Replace:
                    return GL_REPLACE;
                case wgpu::StencilOperation::Invert:
                    return GL_INVERT;
                case wgpu::StencilOperation::IncrementClamp:
                    return GL_INCR;
                case wgpu::StencilOperation::DecrementClamp:
                    return GL_DECR;
                case wgpu::StencilOperation::IncrementWrap:
                    return GL_INCR_WRAP;
                case wgpu::StencilOperation::DecrementWrap:
                    return GL_DECR_WRAP;
            }
            UNREACHABLE();
        }

        void ApplyDepthStencilState(const OpenGLFunctions& gl,
                                    const DepthStencilState* descriptor,
                                    PersistentPipelineState* persistentPipelineState) {
            // Depth writes only occur if depth is enabled
            if (descriptor->depthCompare == wgpu::CompareFunction::Always &&
                !descriptor->depthWriteEnabled) {
                gl.Disable(GL_DEPTH_TEST);
            } else {
                gl.Enable(GL_DEPTH_TEST);
            }

            if (descriptor->depthWriteEnabled) {
                gl.DepthMask(GL_TRUE);
            } else {
                gl.DepthMask(GL_FALSE);
            }

            gl.DepthFunc(ToOpenGLCompareFunction(descriptor->depthCompare));

            if (StencilTestEnabled(descriptor)) {
                gl.Enable(GL_STENCIL_TEST);
            } else {
                gl.Disable(GL_STENCIL_TEST);
            }

            GLenum backCompareFunction = ToOpenGLCompareFunction(descriptor->stencilBack.compare);
            GLenum frontCompareFunction = ToOpenGLCompareFunction(descriptor->stencilFront.compare);
            persistentPipelineState->SetStencilFuncsAndMask(
                gl, backCompareFunction, frontCompareFunction, descriptor->stencilReadMask);

            gl.StencilOpSeparate(GL_BACK, OpenGLStencilOperation(descriptor->stencilBack.failOp),
                                 OpenGLStencilOperation(descriptor->stencilBack.depthFailOp),
                                 OpenGLStencilOperation(descriptor->stencilBack.passOp));
            gl.StencilOpSeparate(GL_FRONT, OpenGLStencilOperation(descriptor->stencilFront.failOp),
                                 OpenGLStencilOperation(descriptor->stencilFront.depthFailOp),
                                 OpenGLStencilOperation(descriptor->stencilFront.passOp));

            gl.StencilMask(descriptor->stencilWriteMask);
        }

    }  // anonymous namespace

    // static
    Ref<RenderPipeline> RenderPipeline::CreateUninitialized(
        Device* device,
        const RenderPipelineDescriptor* descriptor) {
        return AcquireRef(new RenderPipeline(device, descriptor));
    }

    RenderPipeline::RenderPipeline(Device* device, const RenderPipelineDescriptor* descriptor)
        : RenderPipelineBase(device, descriptor),
          mVertexArrayObject(0),
          mGlPrimitiveTopology(GLPrimitiveTopology(GetPrimitiveTopology())) {
    }

    MaybeError RenderPipeline::Initialize() {
        DAWN_TRY(
            InitializeBase(ToBackend(GetDevice())->gl, ToBackend(GetLayout()), GetAllStages()));
        CreateVAOForVertexState();
        return {};
    }

    RenderPipeline::~RenderPipeline() = default;

    void RenderPipeline::DestroyImpl() {
        RenderPipelineBase::DestroyImpl();
        const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
        gl.DeleteVertexArrays(1, &mVertexArrayObject);
        gl.BindVertexArray(0);
        DeleteProgram(gl);
    }

    GLenum RenderPipeline::GetGLPrimitiveTopology() const {
        return mGlPrimitiveTopology;
    }

    ityp::bitset<VertexAttributeLocation, kMaxVertexAttributes>
    RenderPipeline::GetAttributesUsingVertexBuffer(VertexBufferSlot slot) const {
        ASSERT(!IsError());
        return mAttributesUsingVertexBuffer[slot];
    }

    void RenderPipeline::CreateVAOForVertexState() {
        const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;

        gl.GenVertexArrays(1, &mVertexArrayObject);
        gl.BindVertexArray(mVertexArrayObject);

        for (VertexAttributeLocation location : IterateBitSet(GetAttributeLocationsUsed())) {
            const auto& attribute = GetAttribute(location);
            GLuint glAttrib = static_cast<GLuint>(static_cast<uint8_t>(location));
            gl.EnableVertexAttribArray(glAttrib);

            mAttributesUsingVertexBuffer[attribute.vertexBufferSlot][location] = true;
            const VertexBufferInfo& vertexBuffer = GetVertexBuffer(attribute.vertexBufferSlot);

            if (vertexBuffer.arrayStride == 0) {
                // Emulate a stride of zero (constant vertex attribute) by
                // setting the attribute instance divisor to a huge number.
                gl.VertexAttribDivisor(glAttrib, 0xffffffff);
            } else {
                switch (vertexBuffer.stepMode) {
                    case wgpu::VertexStepMode::Vertex:
                        break;
                    case wgpu::VertexStepMode::Instance:
                        gl.VertexAttribDivisor(glAttrib, 1);
                        break;
                }
            }
        }
    }

    void RenderPipeline::ApplyNow(PersistentPipelineState& persistentPipelineState) {
        const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
        PipelineGL::ApplyNow(gl);

        ASSERT(mVertexArrayObject);
        gl.BindVertexArray(mVertexArrayObject);

        ApplyFrontFaceAndCulling(gl, GetFrontFace(), GetCullMode());

        ApplyDepthStencilState(gl, GetDepthStencilState(), &persistentPipelineState);

        gl.SampleMaski(0, GetSampleMask());
        if (IsAlphaToCoverageEnabled()) {
            gl.Enable(GL_SAMPLE_ALPHA_TO_COVERAGE);
        } else {
            gl.Disable(GL_SAMPLE_ALPHA_TO_COVERAGE);
        }

        if (IsDepthBiasEnabled()) {
            gl.Enable(GL_POLYGON_OFFSET_FILL);
            float depthBias = GetDepthBias();
            float slopeScale = GetDepthBiasSlopeScale();
            if (gl.PolygonOffsetClamp != nullptr) {
                gl.PolygonOffsetClamp(slopeScale, depthBias, GetDepthBiasClamp());
            } else {
                gl.PolygonOffset(slopeScale, depthBias);
            }
        } else {
            gl.Disable(GL_POLYGON_OFFSET_FILL);
        }

        if (!GetDevice()->IsToggleEnabled(Toggle::DisableIndexedDrawBuffers)) {
            for (ColorAttachmentIndex attachmentSlot : IterateBitSet(GetColorAttachmentsMask())) {
                ApplyColorState(gl, attachmentSlot, GetColorTargetState(attachmentSlot));
            }
        } else {
            const ColorTargetState* prevDescriptor = nullptr;
            for (ColorAttachmentIndex attachmentSlot : IterateBitSet(GetColorAttachmentsMask())) {
                const ColorTargetState* descriptor = GetColorTargetState(attachmentSlot);
                if (!prevDescriptor) {
                    ApplyColorState(gl, descriptor);
                    prevDescriptor = descriptor;
                } else if ((descriptor->blend == nullptr) != (prevDescriptor->blend == nullptr)) {
                    // TODO(crbug.com/dawn/582): GLES < 3.2 does not support different blend states
                    // per color target. Add validation to prevent this as it is not.
                    ASSERT(false);
                } else if (descriptor->blend != nullptr) {
                    if (!Equal(descriptor->blend->alpha, prevDescriptor->blend->alpha) ||
                        !Equal(descriptor->blend->color, prevDescriptor->blend->color) ||
                        descriptor->writeMask != prevDescriptor->writeMask) {
                        // TODO(crbug.com/dawn/582)
                        ASSERT(false);
                    }
                }
            }
        }
    }

}  // namespace dawn::native::opengl
