// 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/RenderPipeline.h"

#include "common/BitSetIterator.h"
#include "dawn_native/BlendState.h"
#include "dawn_native/DepthStencilState.h"
#include "dawn_native/Device.h"
#include "dawn_native/InputState.h"
#include "dawn_native/RenderPassDescriptor.h"
#include "dawn_native/Texture.h"

namespace dawn_native {

    // RenderPipelineBase

    RenderPipelineBase::RenderPipelineBase(RenderPipelineBuilder* builder)
        : PipelineBase(builder),
          mDepthStencilState(std::move(builder->mDepthStencilState)),
          mIndexFormat(builder->mIndexFormat),
          mInputState(std::move(builder->mInputState)),
          mPrimitiveTopology(builder->mPrimitiveTopology),
          mBlendStates(builder->mBlendStates),
          mColorAttachmentsSet(builder->mColorAttachmentsSet),
          mColorAttachmentFormats(builder->mColorAttachmentFormats),
          mDepthStencilFormatSet(builder->mDepthStencilFormatSet),
          mDepthStencilFormat(builder->mDepthStencilFormat) {
        if (GetStageMask() != (dawn::ShaderStageBit::Vertex | dawn::ShaderStageBit::Fragment)) {
            builder->HandleError("Render pipeline should have exactly a vertex and fragment stage");
            return;
        }

        // TODO(kainino@chromium.org): Need to verify the pipeline against its render subpass.

        if ((builder->GetStageInfo(dawn::ShaderStage::Vertex).module->GetUsedVertexAttributes() &
             ~mInputState->GetAttributesSetMask())
                .any()) {
            builder->HandleError("Pipeline vertex stage uses inputs not in the input state");
            return;
        }

        // TODO(cwallez@chromium.org): Check against the shader module that the correct color
        // attachment are set?

        size_t attachmentCount = mColorAttachmentsSet.count();
        if (mDepthStencilFormatSet) {
            attachmentCount++;
        }

        if (attachmentCount == 0) {
            builder->HandleError("Should have at least one attachment");
            return;
        }
    }

    BlendStateBase* RenderPipelineBase::GetBlendState(uint32_t attachmentSlot) {
        ASSERT(attachmentSlot < mBlendStates.size());
        return mBlendStates[attachmentSlot].Get();
    }

    DepthStencilStateBase* RenderPipelineBase::GetDepthStencilState() {
        return mDepthStencilState.Get();
    }

    dawn::IndexFormat RenderPipelineBase::GetIndexFormat() const {
        return mIndexFormat;
    }

    InputStateBase* RenderPipelineBase::GetInputState() {
        return mInputState.Get();
    }

    dawn::PrimitiveTopology RenderPipelineBase::GetPrimitiveTopology() const {
        return mPrimitiveTopology;
    }

    std::bitset<kMaxColorAttachments> RenderPipelineBase::GetColorAttachmentsMask() const {
        return mColorAttachmentsSet;
    }

    bool RenderPipelineBase::HasDepthStencilAttachment() const {
        return mDepthStencilFormatSet;
    }

    dawn::TextureFormat RenderPipelineBase::GetColorAttachmentFormat(uint32_t attachment) const {
        return mColorAttachmentFormats[attachment];
    }

    dawn::TextureFormat RenderPipelineBase::GetDepthStencilFormat() const {
        return mDepthStencilFormat;
    }

    bool RenderPipelineBase::IsCompatibleWith(const RenderPassDescriptorBase* renderPass) const {
        // TODO(cwallez@chromium.org): This is called on every SetPipeline command. Optimize it for
        // example by caching some "attachment compatibility" object that would make the
        // compatibility check a single pointer comparison.

        if (renderPass->GetColorAttachmentMask() != mColorAttachmentsSet) {
            return false;
        }

        for (uint32_t i : IterateBitSet(mColorAttachmentsSet)) {
            if (renderPass->GetColorAttachment(i).view->GetTexture()->GetFormat() !=
                mColorAttachmentFormats[i]) {
                return false;
            }
        }

        if (renderPass->HasDepthStencilAttachment() != mDepthStencilFormatSet) {
            return false;
        }

        if (mDepthStencilFormatSet &&
            (renderPass->GetDepthStencilAttachment().view->GetTexture()->GetFormat() !=
             mDepthStencilFormat)) {
            return false;
        }

        return true;
    }

    // RenderPipelineBuilder

    RenderPipelineBuilder::RenderPipelineBuilder(DeviceBase* device)
        : Builder(device), PipelineBuilder(this) {
    }

    RenderPipelineBase* RenderPipelineBuilder::GetResultImpl() {
        // TODO(cwallez@chromium.org): the layout should be required, and put the default objects in
        // the device
        if (!mInputState) {
            auto builder = mDevice->CreateInputStateBuilder();
            mInputState = builder->GetResult();
            // Remove the external ref objects are created with
            mInputState->Release();
            builder->Release();
        }
        if (!mDepthStencilState) {
            auto builder = mDevice->CreateDepthStencilStateBuilder();
            mDepthStencilState = builder->GetResult();
            // Remove the external ref objects are created with
            mDepthStencilState->Release();
            builder->Release();
        }

        if ((mBlendStatesSet | mColorAttachmentsSet) != mColorAttachmentsSet) {
            HandleError("Blend state set on unset color attachment");
            return nullptr;
        }

        // Assign all color attachments without a blend state the default state
        // TODO(enga@google.com): Put the default objects in the device
        for (uint32_t attachmentSlot : IterateBitSet(mColorAttachmentsSet & ~mBlendStatesSet)) {
            mBlendStates[attachmentSlot] = mDevice->CreateBlendStateBuilder()->GetResult();
            // Remove the external ref objects are created with
            mBlendStates[attachmentSlot]->Release();
        }

        return mDevice->CreateRenderPipeline(this);
    }

    void RenderPipelineBuilder::SetColorAttachmentFormat(uint32_t attachmentSlot,
                                                         dawn::TextureFormat format) {
        if (attachmentSlot >= kMaxColorAttachments) {
            HandleError("Attachment index out of bounds");
            return;
        }

        mColorAttachmentsSet.set(attachmentSlot);
        mColorAttachmentFormats[attachmentSlot] = format;
    }

    void RenderPipelineBuilder::SetColorAttachmentBlendState(uint32_t attachmentSlot,
                                                             BlendStateBase* blendState) {
        if (attachmentSlot >= kMaxColorAttachments) {
            HandleError("Attachment index out of bounds");
            return;
        }
        if (mBlendStatesSet[attachmentSlot]) {
            HandleError("Attachment blend state already set");
            return;
        }

        mBlendStatesSet.set(attachmentSlot);
        mBlendStates[attachmentSlot] = blendState;
    }

    void RenderPipelineBuilder::SetDepthStencilState(DepthStencilStateBase* depthStencilState) {
        mDepthStencilState = depthStencilState;
    }

    void RenderPipelineBuilder::SetDepthStencilAttachmentFormat(dawn::TextureFormat format) {
        mDepthStencilFormatSet = true;
        mDepthStencilFormat = format;
    }

    void RenderPipelineBuilder::SetIndexFormat(dawn::IndexFormat format) {
        mIndexFormat = format;
    }

    void RenderPipelineBuilder::SetInputState(InputStateBase* inputState) {
        mInputState = inputState;
    }

    void RenderPipelineBuilder::SetPrimitiveTopology(dawn::PrimitiveTopology primitiveTopology) {
        mPrimitiveTopology = primitiveTopology;
    }

}  // namespace dawn_native
