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

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

GrD3DAttachment::GrD3DAttachment(GrD3DGpu* gpu,
                                 SkISize dimensions,
                                 UsageFlags supportedUsages,
                                 DXGI_FORMAT format,
                                 const D3D12_RESOURCE_DESC& desc,
                                 const GrD3DTextureResourceInfo& info,
                                 sk_sp<GrD3DResourceState> state,
                                 const GrD3DDescriptorHeap::CPUHandle& view,
                                 std::string_view label)
        : GrAttachment(gpu,
                       dimensions,
                       supportedUsages,
                       desc.SampleDesc.Count,
                       skgpu::Mipmapped::kNo,
                       GrProtected::kNo,
                       label)
        , GrD3DTextureResource(info, state)
        , fView(view)
        , fFormat(format) {
    this->registerWithCache(skgpu::Budgeted::kYes);
}

sk_sp<GrD3DAttachment> GrD3DAttachment::MakeStencil(GrD3DGpu* gpu,
                                                    SkISize dimensions,
                                                    int sampleCnt,
                                                    DXGI_FORMAT format) {
    D3D12_RESOURCE_DESC resourceDesc = {};
    resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
    resourceDesc.Alignment = 0;  // default alignment
    resourceDesc.Width = dimensions.width();
    resourceDesc.Height = dimensions.height();
    resourceDesc.DepthOrArraySize = 1;
    resourceDesc.MipLevels = 1;
    resourceDesc.Format = format;
    resourceDesc.SampleDesc.Count = sampleCnt;
    resourceDesc.SampleDesc.Quality = DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN;
    resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;  // use driver-selected swizzle
    resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;

    D3D12_CLEAR_VALUE clearValue = {};
    clearValue.Format = format;
    clearValue.DepthStencil.Depth = 0;
    clearValue.DepthStencil.Stencil = 0;

    GrD3DTextureResourceInfo info;
    if (!GrD3DTextureResource::InitTextureResourceInfo(gpu, resourceDesc,
                                                       D3D12_RESOURCE_STATE_DEPTH_WRITE,
                                                       GrProtected::kNo, &clearValue, &info)) {
        return nullptr;
    }

    GrD3DDescriptorHeap::CPUHandle view =
            gpu->resourceProvider().createDepthStencilView(info.fResource.get());

    sk_sp<GrD3DResourceState> state(new GrD3DResourceState(info.fResourceState));
    return sk_sp<GrD3DAttachment>(new GrD3DAttachment(gpu, dimensions,
                                                      UsageFlags::kStencilAttachment,
                                                      format, resourceDesc, info,
                                                      std::move(state),
                                                      view,
                                                      /*label=*/"D3DAttachment_MakeStencil"));
}

void GrD3DAttachment::onRelease() {
    GrD3DGpu* gpu = this->getD3DGpu();
    this->releaseResource(gpu);

    GrAttachment::onRelease();
}

void GrD3DAttachment::onAbandon() {
    GrD3DGpu* gpu = this->getD3DGpu();
    this->releaseResource(gpu);

    GrAttachment::onAbandon();
}

GrD3DGpu* GrD3DAttachment::getD3DGpu() const {
    SkASSERT(!this->wasDestroyed());
    return static_cast<GrD3DGpu*>(this->getGpu());
}

void GrD3DAttachment::onSetLabel() {
    SkASSERT(this->d3dResource());
    if (!this->getLabel().empty()) {
        const std::wstring label = L"_Skia_" + GrD3DMultiByteToWide(this->getLabel());
        this->d3dResource()->SetName(label.c_str());
    }
}
