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

#include "src/gpu/ganesh/d3d/GrD3DOpsRenderPass.h"

#include "src/gpu/ganesh/GrBackendUtils.h"
#include "src/gpu/ganesh/GrOpFlushState.h"
#include "src/gpu/ganesh/GrProgramDesc.h"
#include "src/gpu/ganesh/GrRenderTarget.h"
#include "src/gpu/ganesh/GrStencilSettings.h"
#include "src/gpu/ganesh/d3d/GrD3DBuffer.h"
#include "src/gpu/ganesh/d3d/GrD3DCommandSignature.h"
#include "src/gpu/ganesh/d3d/GrD3DGpu.h"
#include "src/gpu/ganesh/d3d/GrD3DPipelineState.h"
#include "src/gpu/ganesh/d3d/GrD3DPipelineStateBuilder.h"
#include "src/gpu/ganesh/d3d/GrD3DRenderTarget.h"
#include "src/gpu/ganesh/d3d/GrD3DTexture.h"
#include "src/gpu/ganesh/effects/GrTextureEffect.h"

#ifdef SK_DEBUG
#include "include/gpu/ganesh/GrDirectContext.h"
#include "src/gpu/ganesh/GrDirectContextPriv.h"
#endif

using namespace skia_private;

GrD3DOpsRenderPass::GrD3DOpsRenderPass(GrD3DGpu* gpu) : fGpu(gpu) {}

bool GrD3DOpsRenderPass::set(GrRenderTarget* rt, GrSurfaceOrigin origin, const SkIRect& bounds,
                             const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
                             const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
                             const TArray<GrSurfaceProxy*, true>& sampledProxies) {
    SkASSERT(!fRenderTarget);
    SkASSERT(fGpu == rt->getContext()->priv().getGpu());

    this->INHERITED::set(rt, origin);

    fBounds = bounds;

    fColorLoadOp = colorInfo.fLoadOp;
    fClearColor = colorInfo.fClearColor;
    fStencilLoadOp = stencilInfo.fLoadOp;

    // TODO

    return true;
}

GrD3DOpsRenderPass::~GrD3DOpsRenderPass() {}

GrGpu* GrD3DOpsRenderPass::gpu() { return fGpu; }

void GrD3DOpsRenderPass::onBegin() {
    GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(fRenderTarget);
    if (d3dRT->numSamples() > 1) {
        d3dRT->msaaTextureResource()->setResourceState(fGpu, D3D12_RESOURCE_STATE_RENDER_TARGET);
    } else {
        d3dRT->setResourceState(fGpu, D3D12_RESOURCE_STATE_RENDER_TARGET);
    }
    fGpu->currentCommandList()->setRenderTarget(d3dRT);

    if (GrLoadOp::kClear == fColorLoadOp) {
        // Passing in nullptr for the rect clears the entire d3d RT. Is this correct? Does the load
        // op respect the logical bounds of a RT?
        fGpu->currentCommandList()->clearRenderTargetView(d3dRT, fClearColor, nullptr);
    }

    if (auto stencil = d3dRT->getStencilAttachment()) {
        GrD3DAttachment* d3dStencil = static_cast<GrD3DAttachment*>(stencil);
        d3dStencil->setResourceState(fGpu, D3D12_RESOURCE_STATE_DEPTH_WRITE);
        if (fStencilLoadOp == GrLoadOp::kClear) {
            fGpu->currentCommandList()->clearDepthStencilView(d3dStencil, 0, nullptr);
        }
    }
}

void set_stencil_ref(GrD3DGpu* gpu, const GrProgramInfo& info) {
    GrStencilSettings stencilSettings = info.nonGLStencilSettings();
    if (!stencilSettings.isDisabled()) {
        unsigned int stencilRef = 0;
        if (stencilSettings.isTwoSided()) {
            SkASSERT(stencilSettings.postOriginCCWFace(info.origin()).fRef ==
                     stencilSettings.postOriginCWFace(info.origin()).fRef);
            stencilRef = stencilSettings.postOriginCCWFace(info.origin()).fRef;
        } else {
            stencilRef = stencilSettings.singleSidedFace().fRef;
        }
        gpu->currentCommandList()->setStencilRef(stencilRef);
    }
}

void set_blend_factor(GrD3DGpu* gpu, const GrProgramInfo& info) {
    const GrXferProcessor& xferProcessor = info.pipeline().getXferProcessor();
    const skgpu::Swizzle& swizzle = info.pipeline().writeSwizzle();
    const skgpu::BlendInfo& blendInfo = xferProcessor.getBlendInfo();
    skgpu::BlendCoeff srcCoeff = blendInfo.fSrcBlend;
    skgpu::BlendCoeff dstCoeff = blendInfo.fDstBlend;
    float floatColors[4];
    if (skgpu::BlendCoeffRefsConstant(srcCoeff) || skgpu::BlendCoeffRefsConstant(dstCoeff)) {
        // Swizzle the blend to match what the shader will output.
        SkPMColor4f blendConst = swizzle.applyTo(blendInfo.fBlendConstant);
        floatColors[0] = blendConst.fR;
        floatColors[1] = blendConst.fG;
        floatColors[2] = blendConst.fB;
        floatColors[3] = blendConst.fA;
    } else {
        memset(floatColors, 0, 4 * sizeof(float));
    }
    gpu->currentCommandList()->setBlendFactor(floatColors);
}

void set_primitive_topology(GrD3DGpu* gpu, const GrProgramInfo& info) {
    D3D12_PRIMITIVE_TOPOLOGY topology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
    switch (info.primitiveType()) {
        case GrPrimitiveType::kTriangles:
            topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
            break;
        case GrPrimitiveType::kTriangleStrip:
            topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
            break;
        case GrPrimitiveType::kPoints:
            topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
            break;
        case GrPrimitiveType::kLines:
            topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
            break;
        case GrPrimitiveType::kLineStrip:
            topology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
            break;
        default:
            SkUNREACHABLE;
    }
    gpu->currentCommandList()->setPrimitiveTopology(topology);
}

void set_scissor_rects(GrD3DGpu* gpu, const GrRenderTarget* renderTarget, GrSurfaceOrigin rtOrigin,
                       const SkIRect& scissorRect) {
    SkASSERT(scissorRect.isEmpty() ||
             SkIRect::MakeWH(renderTarget->width(), renderTarget->height()).contains(scissorRect));

    D3D12_RECT scissor;
    scissor.left = scissorRect.fLeft;
    scissor.right = scissorRect.fRight;
    if (kTopLeft_GrSurfaceOrigin == rtOrigin) {
        scissor.top = scissorRect.fTop;
    } else {
        SkASSERT(kBottomLeft_GrSurfaceOrigin == rtOrigin);
        scissor.top = renderTarget->height() - scissorRect.fBottom;
    }
    scissor.bottom = scissor.top + scissorRect.height();

    SkASSERT(scissor.left >= 0);
    SkASSERT(scissor.top >= 0);
    gpu->currentCommandList()->setScissorRects(1, &scissor);
}

void set_viewport(GrD3DGpu* gpu, const GrRenderTarget* renderTarget) {
    D3D12_VIEWPORT viewport;
    viewport.TopLeftX = 0.0f;
    viewport.TopLeftY = 0.0f;
    viewport.Width = SkIntToScalar(renderTarget->width());
    viewport.Height = SkIntToScalar(renderTarget->height());
    viewport.MinDepth = 0.0f;
    viewport.MaxDepth = 1.0f;
    gpu->currentCommandList()->setViewports(1, &viewport);
}

bool GrD3DOpsRenderPass::onBindPipeline(const GrProgramInfo& info, const SkRect& drawBounds) {
    SkRect rtRect = SkRect::Make(fBounds);
    if (rtRect.intersect(drawBounds)) {
        rtRect.roundOut(&fCurrentPipelineBounds);
    } else {
        fCurrentPipelineBounds.setEmpty();
    }

    GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(fRenderTarget);
    fCurrentPipelineState =
            fGpu->resourceProvider().findOrCreateCompatiblePipelineState(d3dRT, info);
    if (!fCurrentPipelineState) {
        return false;
    }

    fGpu->currentCommandList()->setGraphicsRootSignature(fCurrentPipelineState->rootSignature());
    fGpu->currentCommandList()->setPipelineState(fCurrentPipelineState->pipeline());
    fCurrentPipelineState->setAndBindConstants(fGpu, fRenderTarget, info);

    set_stencil_ref(fGpu, info);
    set_blend_factor(fGpu, info);
    set_primitive_topology(fGpu, info);
    if (!info.pipeline().isScissorTestEnabled()) {
        // "Disable" scissor by setting it to the full pipeline bounds.
        set_scissor_rects(fGpu, fRenderTarget, fOrigin, fCurrentPipelineBounds);
    }
    set_viewport(fGpu, fRenderTarget);

    return true;
}

void GrD3DOpsRenderPass::onSetScissorRect(const SkIRect& scissor) {
    SkIRect combinedScissorRect;
    if (!combinedScissorRect.intersect(fCurrentPipelineBounds, scissor)) {
        combinedScissorRect = SkIRect::MakeEmpty();
    }

    set_scissor_rects(fGpu, fRenderTarget, fOrigin, combinedScissorRect);
}

void update_resource_state(GrTexture* tex, GrRenderTarget* rt, GrD3DGpu* gpu) {
    SkASSERT(!tex->isProtected() || (rt->isProtected() && gpu->protectedContext()));
    GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(tex);
    SkASSERT(d3dTex);
    d3dTex->setResourceState(gpu, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
}

bool GrD3DOpsRenderPass::onBindTextures(const GrGeometryProcessor& geomProc,
                                        const GrSurfaceProxy* const geomProcTextures[],
                                        const GrPipeline& pipeline) {
    SkASSERT(fCurrentPipelineState);

    // update textures to sampled resource state
    for (int i = 0; i < geomProc.numTextureSamplers(); ++i) {
        update_resource_state(geomProcTextures[i]->peekTexture(), fRenderTarget, fGpu);
    }

    pipeline.visitTextureEffects([&](const GrTextureEffect& te) {
        update_resource_state(te.texture(), fRenderTarget, fGpu);
    });

    if (GrTexture* dstTexture = pipeline.peekDstTexture()) {
        update_resource_state(dstTexture, fRenderTarget, fGpu);
    }

    // TODO: possibly check for success once we start binding properly
    fCurrentPipelineState->setAndBindTextures(fGpu, geomProc, geomProcTextures, pipeline);

    return true;
}

void GrD3DOpsRenderPass::onBindBuffers(sk_sp<const GrBuffer> indexBuffer,
                                       sk_sp<const GrBuffer> instanceBuffer,
                                       sk_sp<const GrBuffer> vertexBuffer,
                                       GrPrimitiveRestart primRestart) {
    SkASSERT(GrPrimitiveRestart::kNo == primRestart);
    SkASSERT(fCurrentPipelineState);
    SkASSERT(!fGpu->caps()->usePrimitiveRestart());  // Ignore primitiveRestart parameter.

    GrD3DDirectCommandList* currCmdList = fGpu->currentCommandList();
    SkASSERT(currCmdList);

    fCurrentPipelineState->bindBuffers(fGpu, std::move(indexBuffer), std::move(instanceBuffer),
                                       std::move(vertexBuffer), currCmdList);
}

void GrD3DOpsRenderPass::onDrawInstanced(int instanceCount, int baseInstance, int vertexCount,
                                            int baseVertex) {
    SkASSERT(fCurrentPipelineState);
    fGpu->currentCommandList()->drawInstanced(vertexCount, instanceCount, baseVertex, baseInstance);
    fGpu->stats()->incNumDraws();
}

void GrD3DOpsRenderPass::onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount,
                                                int baseInstance, int baseVertex) {
    SkASSERT(fCurrentPipelineState);
    fGpu->currentCommandList()->drawIndexedInstanced(indexCount, instanceCount, baseIndex,
                                                     baseVertex, baseInstance);
    fGpu->stats()->incNumDraws();
}

void GrD3DOpsRenderPass::onDrawIndirect(const GrBuffer* buffer, size_t offset, int drawCount) {
    constexpr unsigned int kSlot = 0;
    sk_sp<GrD3DCommandSignature> cmdSig = fGpu->resourceProvider().findOrCreateCommandSignature(
            GrD3DCommandSignature::ForIndexed::kNo, kSlot);
    fGpu->currentCommandList()->executeIndirect(cmdSig, drawCount,
                                                static_cast<const GrD3DBuffer*>(buffer), offset);
    fGpu->stats()->incNumDraws();
}

void GrD3DOpsRenderPass::onDrawIndexedIndirect(const GrBuffer* buffer, size_t offset,
                                               int drawCount) {
    constexpr unsigned int kSlot = 0;
    sk_sp<GrD3DCommandSignature> cmdSig = fGpu->resourceProvider().findOrCreateCommandSignature(
            GrD3DCommandSignature::ForIndexed::kYes, kSlot);
    fGpu->currentCommandList()->executeIndirect(cmdSig, drawCount,
                                                static_cast<const GrD3DBuffer*>(buffer), offset);
    fGpu->stats()->incNumDraws();
}


static D3D12_RECT scissor_to_d3d_clear_rect(const GrScissorState& scissor,
                                            const GrSurface* surface,
                                            GrSurfaceOrigin origin) {
    D3D12_RECT clearRect;
    // Flip rect if necessary
    SkIRect d3dRect;
    if (!scissor.enabled()) {
        d3dRect.setXYWH(0, 0, surface->width(), surface->height());
    } else if (kBottomLeft_GrSurfaceOrigin != origin) {
        d3dRect = scissor.rect();
    } else {
        d3dRect.setLTRB(scissor.rect().fLeft, surface->height() - scissor.rect().fBottom,
                        scissor.rect().fRight, surface->height() - scissor.rect().fTop);
    }
    clearRect.left = d3dRect.fLeft;
    clearRect.right = d3dRect.fRight;
    clearRect.top = d3dRect.fTop;
    clearRect.bottom = d3dRect.fBottom;
    return clearRect;
}

void GrD3DOpsRenderPass::onClear(const GrScissorState& scissor, std::array<float, 4> color) {
    D3D12_RECT clearRect = scissor_to_d3d_clear_rect(scissor, fRenderTarget, fOrigin);
    auto d3dRT = static_cast<GrD3DRenderTarget*>(fRenderTarget);
    SkASSERT(d3dRT->grD3DResourceState()->getResourceState() == D3D12_RESOURCE_STATE_RENDER_TARGET);
    fGpu->currentCommandList()->clearRenderTargetView(d3dRT, color, &clearRect);
}

void GrD3DOpsRenderPass::onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) {
    GrAttachment* sb = fRenderTarget->getStencilAttachment();
    // this should only be called internally when we know we have a
    // stencil buffer.
    SkASSERT(sb);
    int stencilBitCount = GrBackendFormatStencilBits(sb->backendFormat());

    // The contract with the callers does not guarantee that we preserve all bits in the stencil
    // during this clear. Thus we will clear the entire stencil to the desired value.

    uint8_t stencilColor = 0;
    if (insideStencilMask) {
        stencilColor = (1 << (stencilBitCount - 1));
    }

    D3D12_RECT clearRect = scissor_to_d3d_clear_rect(scissor, fRenderTarget, fOrigin);

    auto d3dStencil = static_cast<GrD3DAttachment*>(sb);
    fGpu->currentCommandList()->clearDepthStencilView(d3dStencil, stencilColor, &clearRect);
}

bool GrD3DOpsRenderPass::inlineUpload(GrOpFlushState* state, GrDeferredTextureUploadFn& upload) {
    // If we ever start using copy command lists for doing uploads, then we'll need to make sure
    // we submit our main command list before doing the copy here and then start a new main command
    // list.
    fGpu->endRenderPass(fRenderTarget, fOrigin, fBounds);

    // We pass in true here to signal that after the upload we need to set the upload texture's
    // resource state back to D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE.
    state->doUpload(upload, true);

    return true;
}

void GrD3DOpsRenderPass::submit() {
    if (!fRenderTarget) {
        return;
    }

    // We don't use render passes in d3d, so there is nothing to submit here as all commands have
    // already been recorded on the main command list. If in the future we start to use render
    // passes on d3d12 devices that support them (most likely ARM devices), then we
    // will submit them here.
    fGpu->endRenderPass(fRenderTarget, fOrigin, fBounds);
}
