// 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 { namespace 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;
            }
        }

        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;

                // Deprecated blend factors should be normalized prior to this call.
                case wgpu::BlendFactor::SrcColor:
                case wgpu::BlendFactor::OneMinusSrcColor:
                case wgpu::BlendFactor::DstColor:
                case wgpu::BlendFactor::OneMinusDstColor:
                case wgpu::BlendFactor::BlendColor:
                case wgpu::BlendFactor::OneMinusBlendColor:
                    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;
            }
        }

        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 BlendDescriptor& lhs, const BlendDescriptor& 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;
            }
        }

        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
    ResultOrError<Ref<RenderPipeline>> RenderPipeline::Create(
        Device* device,
        const RenderPipelineDescriptor* descriptor) {
        Ref<RenderPipeline> pipeline = AcquireRef(new RenderPipeline(device, descriptor));
        DAWN_TRY(pipeline->Initialize());
        return pipeline;
    }

    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() {
        const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
        gl.DeleteVertexArrays(1, &mVertexArrayObject);
        gl.BindVertexArray(0);
    }

    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
