/*
 * Copyright 2026 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/graphite/DrawListLayer.h"

#include "include/core/SkTypes.h"
#include "include/gpu/graphite/Recorder.h"
#include "src/core/SkTraceEvent.h"
#include "src/gpu/graphite/DrawPass.h"
#include "src/gpu/graphite/DrawWriter.h"
#include "src/gpu/graphite/KeyContext.h"
#include "src/gpu/graphite/RecorderPriv.h"
#include "src/gpu/graphite/Renderer.h"
#include "src/gpu/graphite/geom/Geometry.h"

namespace skgpu::graphite {

void DrawListLayer::reset(LoadOp loadOp, SkColor4f color) {
    DrawListBase::reset(loadOp, color);

    fStorage.reset();
    fLayers.reset();
    fDrawCount = 0;
    fOrderCounter = CompressedPaintersOrder::First();
}

std::pair<Layer*, BindingList*> DrawListLayer::searchBackwards(
        const RenderStep* step,
        const LayerKey& key,
        SkEnumBitMask<BoundsFlags> testMask,
        const DrawParams* drawParams,
        CompressedPaintersOrder stop) {
    // CPU performance is sensitive to increasing this value. Searching for longer *can* reduce the
    // draw count and pipeline change count
    static constexpr int kMaxSearchLimit = 8;

    Rect::ComplementRect drawBounds{drawParams->drawBounds()};

    Layer* targetLayer = nullptr;
    Layer* current = fLayers.tail();
    for (int limit = kMaxSearchLimit; limit > 0 && current; --limit) {
        // NOTE: This test does not search within the layer's binding lists for a match. Searching
        // each layer that can allow the draw adds overhead for minimal batching improvements.
        // Instead the heuristic to just add to the deepest layer possible and search only that
        // layer for a good binding match batches about as well in the limit.
        auto result = current->test(drawBounds, testMask);

        if (result & BoundsTestResult::kAllowedInLayer) {
            // Allowed in the layer, so remember it. In complex scenes, we want to search deeper
            // in the layer list than just the first compatible overlap we encounter. Stopping early
            // reduces search time but fragments batching. Inserting early blocks subsequent draws
            // from reaching those denser, later candidates (particularly when this is a clip draw
            // as that propagates into the stop layer for subsequent draws).
            targetLayer = current;
        }

        if (!SkToBool(result & BoundsTestResult::kAllowedBeforeLayer) || current->fOrder == stop) {
            break;
        } else {
            current = current->fPrev;
        }
    }

    SkASSERT(!targetLayer || targetLayer->fOrder >= stop);

    BindingList* targetMatch = nullptr;
    BindingList* forwardMerge = nullptr;
    if (targetLayer) {
        // `targetLayer` is non-null only if the test returned kAllowedInLayer, which means it is
        // disjoint from everything else in the layer. We can safely combine it with an exact match
        // or place it near a partial match.
        targetMatch = targetLayer->searchBinding(key);
        // if `targetMatch` is null, we could try and search `current` for a match but it would only
        // be valid if the key is simple-shading and the match was the last, at which point we can
        // allow for overlap. We could also try to do a more detailed per-binding list bounds check
        // to see if the draw could skip past some of the bindings to find a match. However, since
        // we have a targetLayer already, `current` would only be one deeper, so it's often not
        // worth the trade off of additional search time.
        // FIXME this didn't come up with just checking the tail binding, but maybe if we did
        // per binding list bounds checks, we would find more matches?
    } else if (key.isSimpleShading() && fLayers.tail()) {
        // As a simple-shading draw, there is the potential to pull a previous binding list
        // forward to a new layer. This must be an exact match so that we can rely on rasterization
        // order resolving any overlap (since !targetLayer implies the test originally failed for
        // fLayers.tail()).
        if ((forwardMerge = fLayers.tail()->searchBinding(key))) {
            if (!forwardMerge->fKey.isEqual(key)) {
                forwardMerge = nullptr;
            } else if (!forwardMerge->fPrev && !forwardMerge->fNext) {
                // The tail had a single exact matching binding list, so just append to it. There
                // are no other incompatible bindings whose overlap we need to worry about.
                targetLayer = fLayers.tail();
                targetMatch = forwardMerge;
                forwardMerge = nullptr;
            } // else we'll transfer the forward merge list into a new layer below
        } // else didn't find a match in the last layer
    } // else not forward-merge eligible and no target, so we'll put it in a new layer

    if (!targetLayer) {
        fOrderCounter = fOrderCounter.next();
        targetLayer = fStorage.make<Layer>(fOrderCounter);
        if (forwardMerge) {
            fLayers.tail()->transfer(forwardMerge, targetLayer);
            targetMatch = forwardMerge;
        }
        fLayers.addToTail(targetLayer);
    }

    if (!targetMatch || !targetMatch->fKey.isEqual(key)) {
        // If targetMatch is just a pipeline match, we can insert right before it because such a
        // match is only returned when the new draw can be ordered in front of it.
        targetMatch = targetLayer->addNewBinding(&fStorage, targetMatch, key, step);
    } else {
        SkASSERT(targetLayer->fBindings.isInList(targetMatch));
    }

    return {targetLayer, targetMatch};
}

BindingList* DrawListLayer::findOrCreateBindingInLayer(Layer* layer,
                                                       BindingList* parent,
                                                       const RenderStep* step,
                                                       const LayerKey& key) {
    // If we're recording a new step in the layer, there better have been a draw that searched
    // backwards for the layer first!
    SkASSERT(layer);
    // If we have a parent step's BindingList to insert before, it must be in `layer`.
    SkASSERT(!parent || layer->fBindings.isInList(parent));

    BindingList* targetMatch = nullptr;

    // If we don't have a parent, search through all bindings of the layer as this is the first time
    // through the layer. If we do have a parent, search through the preceding bindings (exclusive).
    // This is handled automatically by searchBinding's `parent` handling; when there are no
    // preceding bindings (e.g. parent && !parent->fPrev), `match` will just be null.
    BindingList* match = layer->searchBinding(key, parent);
    if (match) {
        if (match->fKey.isEqual(key)) {
            targetMatch = match;
        } else {
            // NOTE: Treat any pipeline match as the new parent that a new binding list will be
            // inserted before. Since the search started from the original parent (exclusive),
            // any found pipeline match will still be before that parent.
            parent = match;
        }
    }

    if (!targetMatch) {
        targetMatch = layer->addNewBinding(&fStorage, parent, key, step);
    }
    return targetMatch;
}

// Layer has dual purpose here:
//  1) (Producer) If recording a depth-only draw, the returned Layer* pointer is remembered as
//     the earliest possible layer that a later clipped draw can be added to. This is stored on the
//     ClipStack::Element that produced the depth-only draw.
//  2) (Consumer) If recording a clipped draw, the pointer is the latest layer inserted into across
//     *all depth only draws* which affect this draw. If the draw has no other bounds dependencies,
//     this represents the Layer that it can be directly added to.
std::pair<DrawParams*, Layer*> DrawListLayer::recordDraw(const Renderer* renderer,
                                                         const Transform& localToDevice,
                                                         const Geometry& geometry,
                                                         const Clip& clip,
                                                         DrawOrder ordering,
                                                         UniquePaintParamsID paintID,
                                                         SkEnumBitMask<DstUsage> dstUsage,
                                                         BarrierType barrierBeforeDraws,
                                                         PipelineDataGatherer* gatherer,
                                                         StorageContext* storageContext,
                                                         const StrokeStyle* stroke,
                                                         Layer* lastInsertion) {
    SkASSERT(localToDevice.valid());
    SkASSERT(!geometry.isEmpty() && !clip.drawBounds().isEmptyNegativeOrNaN());

    // `testMask` limits what we test against when searching backwards, which is based on the
    // Renderer's aggregate requirements so that the layer we find will be valid for all steps. This
    // is particularly important for stencil-based renderers, which consist of a non-shading
    // "producer" step, which writes into the stencil buffer, and shading "consumer" render steps
    // which test against the stencil mask and clear the buffer afterwards. This guarantees
    // atomicity within a single layer, where the last step finds a safe layer and all earlier steps
    // are explicitly inserted before that. This minimizes pipeline switches as rendering can
    // proceed through the steps in bulk.
    SkEnumBitMask<BoundsFlags> testMask;
    if (SkToBool(renderer->depthStencilFlags() & DepthStencilFlags::kStencil)) {
        testMask |= BoundsFlags::kStencil;
    }
    // Draws that blend must respect painter's order, and clipping depth-only draws cannot be
    // ordered in front of shading draws.
    const bool isDepthOnly = !paintID.isValid();
    const bool dependsOnDst = SkToBool(dstUsage & DstUsage::kDependsOnDst);
    if (dependsOnDst || isDepthOnly) {
        testMask |= BoundsFlags::kColor;
    }

    // In simple situations, we can allow overlaps within a BindingList and let GPU rasterization
    // resolve the rendering order automatically. This does not apply if barriers are required,
    // and it does not apply when the Renderer has multiple steps (must keep the sets of draws in
    // each step disjoint so there isn't interference).
    SkEnumBitMask<BoundsFlags> baseLayerMask = BoundsFlags::kNone;
    if (barrierBeforeDraws != BarrierType::kNone || renderer->numRenderSteps() > 1) {
        baseLayerMask |= BoundsFlags::kMustBeDisjoint;
    }

    // Currently, the draw params are created once per record draw call, and the pointer is passed
    // to each draw call. This is storage effecient but will still introduce some pointer chasing,
    // because the params will likely no longer be on the same cache line for successor render
    // steps. We should test whether it is faster for each step to hold a copy of the params except
    // in the case of clipped draws (which must share a copy because they are mutated later).
    DrawParams* drawParams = fStorage.make<DrawParams>(this->deduplicateTransform(localToDevice),
                                                       geometry,
                                                       clip,
                                                       ordering,
                                                       stroke,
                                                       barrierBeforeDraws);

    Layer* insertionLayer = nullptr;
    BindingList* lastStepBinding = nullptr;
    // If we're an easy draw, jump to the latestInsertion layer since we don't have to test
    if (testMask == BoundsFlags::kNone && baseLayerMask == BoundsFlags::kNone) {
        insertionLayer = lastInsertion ? lastInsertion : fLayers.head();
    }

    SkEnumBitMask<BoundsFlags> allLayerMasks;
    for (int stepIndex = renderer->numRenderSteps() - 1; stepIndex >= 0; --stepIndex) {
        const RenderStep* const step = renderer->steps()[stepIndex];
        const bool performsShading = step->performsShading() && paintID.isValid();

        if (storageContext && step->storageUniformStride() > 0) {
            storageContext->recordAlignment(step->storageUniformStride(),
                                            step->storageUniformAlignment());
        }

        gatherer->markOffsetAndAlign(performsShading, step->uniformAlignment());

        GraphicsPipelineCache::Index pipelineIndex = fPipelineCache.insert(
                {step->renderStepID(),
                 performsShading ? paintID : UniquePaintParamsID::Invalid()});

        step->writeUniformsAndTextures(*drawParams, gatherer);

        auto [combinedUniforms, combinedTextures] =
                gatherer->endCombinedData(performsShading);

        UniformDataCache::Index uniformIndex = combinedUniforms
                                                       ? fUniformDataCache.insert(combinedUniforms)
                                                       : UniformDataCache::kInvalidIndex;
        TextureDataCache::Index textureBindingIndex =
                combinedTextures ? fTextureDataCache.insert(combinedTextures)
                                 : TextureDataCache::kInvalidIndex;

        // `layerMask` defines what this draw will block in new draws from going backwards. This is
        // per-step so that stencil-only draws can be grouped between shading and clip draws.
        SkEnumBitMask<BoundsFlags> layerMask = baseLayerMask;
        if (step->depthStencilFlags() & DepthStencilFlags::kStencil) {
            layerMask |= BoundsFlags::kStencil;
        }
        if (step->performsShading() && paintID.isValid()) {
            // NOTE: This is not dependsOnDst because it represents what is written by the draw,
            // not what might be read for blending the draw.
            layerMask |= BoundsFlags::kColor;
        }

        LayerKey key{pipelineIndex,
                     textureBindingIndex,
                     fStorageBufferSupport ? UniformDataCache::kInvalidIndex : uniformIndex,
                     layerMask};
        allLayerMasks |= layerMask;

        if (!insertionLayer) {
            // Since we don't have a layer yet, search from the most recent layer back.
            CompressedPaintersOrder stop = lastInsertion ? lastInsertion->fOrder
                                                         : DrawOrder::kNoIntersection;
            std::tie(insertionLayer, lastStepBinding) = this->searchBackwards(step,
                                                                              key,
                                                                              testMask,
                                                                              drawParams,
                                                                              stop);
        } else {
            // Put the earlier steps in the same layer (valid because we used BoundsFlags for the
            // whole Renderer).
            lastStepBinding = this->findOrCreateBindingInLayer(insertionLayer,
                                                               lastStepBinding,
                                                               step,
                                                               key);
        }

        SkASSERT(lastStepBinding);
        lastStepBinding->addDraw(&fStorage, drawParams, uniformIndex, /*backToFront=*/dependsOnDst);

        gatherer->rewindForRenderStep();
    }

    // This must be called once for the layer the draw's rendersteps were added into, so do it at
    // the end since we'll always have the layer at this point. This uses bounds flags applying
    // to whole Renderer.
    SkASSERT(insertionLayer);
    insertionLayer->updateForDraw(drawParams->drawBounds(), allLayerMasks);

    fRenderStepCount += renderer->numRenderSteps();
    fDrawCount++;
    fPassBounds.join(clip.drawBounds());
    fRequiresMSAA |= renderer->requiresMSAA();
    fDepthStencilFlags |= renderer->depthStencilFlags();
    if (dstUsage & DstUsage::kDstReadRequired) {
        // For paints that read from the dst, update the bounds. It may later be determined that the
        // DstReadStrategy does not require them, but they are inexpensive to track.
        fDstReadBounds.join(clip.drawBounds());
    }

#if defined(SK_DEBUG)
    if (geometry.isCoverageMaskShape()) {
        fCoverageMaskShapeDrawCount++;
    }
#endif

    return {drawParams, insertionLayer};
}

std::unique_ptr<DrawPass> DrawListLayer::snapDrawPass(Recorder* recorder,
                                                      StorageContext* storageContext,
                                                      DrawContext* drawContext,
                                                      sk_sp<TextureProxy> target,
                                                      const SkImageInfo& targetInfo,
                                                      const DstReadStrategy dstReadStrategy) {
    TRACE_EVENT1_ALWAYS("skia.gpu", "Snap DrawPass", "draw count", fDrawCount);

    std::unique_ptr<DrawPass> drawPass(new DrawPass(target,
                                                    {fLoadOp, StoreOp::kStore},
                                                    fClearColor));
    DrawBufferManager* bufferMgr = recorder->priv().drawBufferManager();
    DrawWriter drawWriter(&drawPass->fCommandList, bufferMgr);

    UniformTracker uniformTracker(fStorageBufferSupport);
    TextureTracker textureBindingTracker(&fTextureDataCache);

    const bool rebindTexturesOnPipelineChange = dstReadStrategy == DstReadStrategy::kTextureCopy;

    if (storageContext) {
        storageContext->finalizePrecachedStorageData();
    }

    GraphicsPipelineCache::Index lastPipeline = GraphicsPipelineCache::kInvalidIndex;
    const SkIRect targetBounds = SkIRect::MakeSize(targetInfo.dimensions());
    SkIRect lastScissor = targetBounds;

    SkASSERT(drawPass->fTarget->isFullyLazy() ||
             SkIRect::MakeSize(drawPass->fTarget->dimensions()).contains(lastScissor));
    drawPass->fCommandList.setScissor(lastScissor);
    // Accumulate rough pixel area touched by each pipeline
    drawPass->fPipelineDrawAreas.push_back_n(fPipelineCache.count(), 0.f);

    auto recordDraw = [&](const LayerKey& key,
                          const RenderStep* renderStep,
                          const Draw* draw,
                          bool bindingsAreInvariant,
                          bool startOfLayer) -> const Draw* {
        SkASSERT(renderStep && draw);
        const DrawParams& drawParams = *draw->fDrawParams;

        bool pipelineChange = false;
        bool textureBindingsChange = false;

        if (!bindingsAreInvariant) {
            pipelineChange = key.fPipelineIndex != lastPipeline;

            textureBindingsChange =
                    textureBindingTracker.setCurrentTextureBindings(key.fTextureIndex) ||
                    (rebindTexturesOnPipelineChange && pipelineChange &&
                     key.fTextureIndex != TextureDataCache::kInvalidIndex);
        }

        // Uniforms are binding invariant when SSBOs are disabled, but it's simpler to just let
        // `uniformBindingChange` eval to false more often. The uniform index must come from the
        // Draw to get the right value when SSBOs are enabled.
        bool uniformBindingChange =
                uniformTracker.writeUniforms(fUniformDataCache, bufferMgr, draw->fUniformIndex);

        drawPass->fPipelineDrawAreas[key.fPipelineIndex] += drawParams.drawBounds().area();

        std::optional<SkIRect> newScissor =
                renderStep->getScissor(drawParams, lastScissor, targetBounds);

        if (pipelineChange) {
            drawWriter.newPipelineState(renderStep->primitiveType(),
                                        renderStep->staticDataStride(),
                                        renderStep->appendDataStride(drawParams),
                                        renderStep->getRenderStateFlags(),
                                        drawParams.barrierBeforeDraws());
        } else if (uniformBindingChange || textureBindingsChange || newScissor.has_value()) {
            drawWriter.newDynamicState();
        } else if (drawParams.barrierBeforeDraws() != BarrierType::kNone && startOfLayer) {
            // Taking this branch means there were no state or pipeline changes between old layer
            // and this layer's first draw. This only happens if the draws overlap, so flush the
            // drawWriter since the draw requires a barrier.
            drawWriter.flush();
        }

        if (pipelineChange) {
            drawPass->fCommandList.bindGraphicsPipeline(key.fPipelineIndex);
            lastPipeline = key.fPipelineIndex;
        }
        if (uniformBindingChange) {
            uniformTracker.bindUniforms(UniformSlot::kCombinedUniforms, &drawPass->fCommandList);
        }
        if (textureBindingsChange) {
            textureBindingTracker.bindTextures(&drawPass->fCommandList);
        }
        if (newScissor.has_value()) {
            drawPass->fCommandList.setScissor(*newScissor);
            lastScissor = *newScissor;
        }

        uint32_t uniformSsboIndex = fStorageBufferSupport ? uniformTracker.ssboIndex() : 0;
        renderStep->writeVertices(&drawWriter, storageContext, drawParams, uniformSsboIndex);

        // Either stop early on failure, or advance to the next Draw
        return bufferMgr->hasMappingFailed() ? nullptr : draw->fNext;
    };

    for (Layer* layer : fLayers) {
        for (const BindingList* list : layer->fBindings) {
            SkASSERT(list->fHead); // not empty

            // The first draw of the BindingList will be changing bindings
            const Draw* current = recordDraw(list->fKey, list->fStep, list->fHead,
                                             /*bindingsAreInvariant=*/false,
                                             /*startOfLayer=*/!list->fPrev);
            while (current) {
                // Any remaining draws can skip checking for pipeline/texture binding changes.
                current = recordDraw(list->fKey, list->fStep, current,
                                     /*bindingsAreInvariant=*/true,
                                     /*startOfLayer=*/false);
            }
        }
    }

    drawWriter.flush();

    if (bufferMgr->hasMappingFailed()) {
        SKIA_LOG_W("Failed to write necessary vertex/instance data for DrawPass, dropping!");
        this->reset(LoadOp::kLoad);
        return nullptr;
    }

    if (storageContext) {
        const bool hasStorageData = !storageContext->isEmpty();
        auto storageResult = storageContext->finalize(recorder, drawContext);
        if (hasStorageData && !storageResult) SK_UNLIKELY {
            SKIA_LOG_W("Failed to write Storage Data for Draw pass, dropping!");
            this->reset(LoadOp::kLoad);
            return nullptr;
        }
        if (storageResult) {
            drawPass->setStorageResult(std::move(*storageResult));
        }
    }

    drawPass->fBounds = fPassBounds.roundOut().asSkIRect();
    drawPass->fPipelineDescs = fPipelineCache.detach();
    drawPass->fSampledTextures = fTextureDataCache.detachTextures();

    TRACE_EVENT_INSTANT2("skia.gpu",
                         "DrawPass Stats",
                         TRACE_EVENT_SCOPE_THREAD,
                         "# commands", drawPass->fCommandList.count(),
                         "# textures", drawPass->fSampledTextures.size());

    this->reset(LoadOp::kLoad);

    return drawPass;
}

}  // namespace skgpu::graphite
