/*
 * 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/d3d/GrD3DDescriptorTableManager.h"

#include "src/gpu/d3d/GrD3DGpu.h"

GrD3DDescriptorTableManager::GrD3DDescriptorTableManager(GrD3DGpu* gpu)
    : fCBVSRVUAVDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
    , fSamplerDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER) {}

sk_sp<GrD3DDescriptorTable>
        GrD3DDescriptorTableManager::createCBVSRVUAVTable(GrD3DGpu* gpu,
                                                                         unsigned int size) {
    sk_sp<GrD3DDescriptorTable> table = fCBVSRVUAVDescriptorPool.allocateTable(gpu, size);
    this->setHeaps(gpu);
    return table;
}

sk_sp<GrD3DDescriptorTable> GrD3DDescriptorTableManager::createSamplerTable(
        GrD3DGpu* gpu, unsigned int size) {
    sk_sp<GrD3DDescriptorTable> table = fSamplerDescriptorPool.allocateTable(gpu, size);
    this->setHeaps(gpu);
    return table;
}

void GrD3DDescriptorTableManager::setHeaps(GrD3DGpu* gpu) {
    sk_sp<Heap>& currentCBVSRVHeap = fCBVSRVUAVDescriptorPool.currentDescriptorHeap();
    sk_sp<Heap>& currentSamplerHeap = fSamplerDescriptorPool.currentDescriptorHeap();
    GrD3DDirectCommandList* commandList = gpu->currentCommandList();
    commandList->setDescriptorHeaps(currentCBVSRVHeap,
                                    currentCBVSRVHeap->d3dDescriptorHeap(),
                                    currentSamplerHeap,
                                    currentSamplerHeap->d3dDescriptorHeap());
}

void GrD3DDescriptorTableManager::prepForSubmit(GrD3DGpu* gpu) {
    fCBVSRVUAVDescriptorPool.prepForSubmit(gpu);
    fSamplerDescriptorPool.prepForSubmit(gpu);
}

void GrD3DDescriptorTableManager::recycle(Heap* heap) {
    // wrap the heap in an sk_sp and take ownership of it
    sk_sp<Heap> wrappedHeap(heap);

    SkASSERT(heap);
    switch (heap->type()) {
        case D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV:
            fCBVSRVUAVDescriptorPool.recycle(std::move(wrappedHeap));
            break;
        case D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER:
            fSamplerDescriptorPool.recycle(std::move(wrappedHeap));
            break;
        default:
            SkUNREACHABLE;
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////

sk_sp<GrD3DDescriptorTableManager::Heap> GrD3DDescriptorTableManager::Heap::Make(
        GrD3DGpu* gpu, D3D12_DESCRIPTOR_HEAP_TYPE type, unsigned int descriptorCount) {
    std::unique_ptr<GrD3DDescriptorHeap> heap =
            GrD3DDescriptorHeap::Make(gpu, type, descriptorCount,
                                      D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE);
    if (!heap) {
        return nullptr;
    }

    return sk_sp< GrD3DDescriptorTableManager::Heap>(new Heap(gpu, heap, type, descriptorCount));
}

sk_sp<GrD3DDescriptorTable> GrD3DDescriptorTableManager::Heap::allocateTable(
        unsigned int count) {
    SkASSERT(fDescriptorCount - fNextAvailable >= count);
    unsigned int startIndex = fNextAvailable;
    fNextAvailable += count;
    return sk_sp<GrD3DDescriptorTable>(
            new GrD3DDescriptorTable(fHeap->getCPUHandle(startIndex).fHandle,
                                     fHeap->getGPUHandle(startIndex).fHandle, fType));
}

void GrD3DDescriptorTableManager::Heap::onRecycle() const {
    fGpu->resourceProvider().descriptorTableMgr()->recycle(const_cast<Heap*>(this));
}

////////////////////////////////////////////////////////////////////////////////////////////////

GrD3DDescriptorTableManager::HeapPool::HeapPool(GrD3DGpu* gpu, D3D12_DESCRIPTOR_HEAP_TYPE heapType)
    : fHeapType(heapType)
    , fCurrentHeapDescriptorCount(kInitialHeapDescriptorCount) {
    sk_sp<Heap> heap = Heap::Make(gpu, fHeapType, fCurrentHeapDescriptorCount);
    fDescriptorHeaps.push_back(heap);
}

sk_sp<GrD3DDescriptorTable> GrD3DDescriptorTableManager::HeapPool::allocateTable(
        GrD3DGpu* gpu, unsigned int count) {
    // In back-to-front order, iterate through heaps until we find one we can allocate from.
    // Any heap we can't allocate from gets removed from the list.
    // If it was already used, it will have been added to the commandlist,
    // and then later recycled back to us.
    while (fDescriptorHeaps.size() > 0) {
        if (fDescriptorHeaps[fDescriptorHeaps.size() - 1]->canAllocate(count)) {
            return fDescriptorHeaps[fDescriptorHeaps.size() - 1]->allocateTable(count);
        }
        // No space in current heap, pop off list
        fDescriptorHeaps.pop_back();
    }

    // Out of available heaps, need to allocate a new one
    fCurrentHeapDescriptorCount = std::min(2*fCurrentHeapDescriptorCount, 2048u);
    sk_sp<GrD3DDescriptorTableManager::Heap> heap =
            GrD3DDescriptorTableManager::Heap::Make(gpu, fHeapType, fCurrentHeapDescriptorCount);
    fDescriptorHeaps.push_back(heap);
    return fDescriptorHeaps[fDescriptorHeaps.size() - 1]->allocateTable(count);
}

sk_sp<GrD3DDescriptorTableManager::Heap>&
        GrD3DDescriptorTableManager::HeapPool::currentDescriptorHeap() {
    SkASSERT(fDescriptorHeaps.size() > 0);
    return fDescriptorHeaps[fDescriptorHeaps.size() - 1];
}

void GrD3DDescriptorTableManager::HeapPool::prepForSubmit(GrD3DGpu* gpu) {
    // Pop off the current descriptor heap
    if (fDescriptorHeaps[fDescriptorHeaps.size() - 1]->used()) {
        fDescriptorHeaps.pop_back();
    }

    if (fDescriptorHeaps.size() == 0) {
        fCurrentHeapDescriptorCount = std::min(fCurrentHeapDescriptorCount, 2048u);
        sk_sp<GrD3DDescriptorTableManager::Heap> heap =
            GrD3DDescriptorTableManager::Heap::Make(gpu, fHeapType, fCurrentHeapDescriptorCount);
        fDescriptorHeaps.push_back(heap);
    }
}

void GrD3DDescriptorTableManager::HeapPool::recycle(sk_sp<Heap> heap) {
    SkASSERT(heap);
    // only add heaps back if they match our current size
    // this purges any smaller heaps we no longer need
    if (heap->descriptorCount() == fCurrentHeapDescriptorCount) {
        heap->reset();
        fDescriptorHeaps.push_back(heap);
    }
}
