1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2020 Google LLC
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/gpu/GrGpuResourcePriv.h"
9cb93a386Sopenharmony_ci#include "src/gpu/d3d/GrD3DAMDMemoryAllocator.h"
10cb93a386Sopenharmony_ci#include "src/gpu/d3d/GrD3DGpu.h"
11cb93a386Sopenharmony_ci#include "src/gpu/d3d/GrD3DTextureResource.h"
12cb93a386Sopenharmony_ci
13cb93a386Sopenharmony_civoid GrD3DTextureResource::setResourceState(const GrD3DGpu* gpu,
14cb93a386Sopenharmony_ci                                            D3D12_RESOURCE_STATES newResourceState,
15cb93a386Sopenharmony_ci                                            unsigned int subresource) {
16cb93a386Sopenharmony_ci    D3D12_RESOURCE_STATES currentResourceState = this->currentState();
17cb93a386Sopenharmony_ci    if (newResourceState == currentResourceState) {
18cb93a386Sopenharmony_ci        return;
19cb93a386Sopenharmony_ci    }
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_ci    D3D12_RESOURCE_TRANSITION_BARRIER barrier;
22cb93a386Sopenharmony_ci    barrier.pResource = this->d3dResource();
23cb93a386Sopenharmony_ci    barrier.Subresource = subresource;
24cb93a386Sopenharmony_ci    barrier.StateBefore = currentResourceState;
25cb93a386Sopenharmony_ci    barrier.StateAfter = newResourceState;
26cb93a386Sopenharmony_ci    gpu->addResourceBarriers(this->resource(), 1, &barrier);
27cb93a386Sopenharmony_ci
28cb93a386Sopenharmony_ci    this->updateResourceState(newResourceState);
29cb93a386Sopenharmony_ci}
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_cibool GrD3DTextureResource::InitTextureResourceInfo(GrD3DGpu* gpu, const D3D12_RESOURCE_DESC& desc,
32cb93a386Sopenharmony_ci                                                   D3D12_RESOURCE_STATES initialState,
33cb93a386Sopenharmony_ci                                                   GrProtected isProtected,
34cb93a386Sopenharmony_ci                                                   D3D12_CLEAR_VALUE* clearValue,
35cb93a386Sopenharmony_ci                                                   GrD3DTextureResourceInfo* info) {
36cb93a386Sopenharmony_ci    if (0 == desc.Width || 0 == desc.Height) {
37cb93a386Sopenharmony_ci        return false;
38cb93a386Sopenharmony_ci    }
39cb93a386Sopenharmony_ci    // TODO: We don't support protected memory at the moment
40cb93a386Sopenharmony_ci    if (isProtected == GrProtected::kYes) {
41cb93a386Sopenharmony_ci        return false;
42cb93a386Sopenharmony_ci    }
43cb93a386Sopenharmony_ci    // If MipLevels is 0, for some formats the API will automatically calculate the maximum
44cb93a386Sopenharmony_ci    // number of levels supported and use that -- we don't support that.
45cb93a386Sopenharmony_ci    SkASSERT(desc.MipLevels > 0);
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ci    info->fResource = gpu->memoryAllocator()->createResource(
48cb93a386Sopenharmony_ci            D3D12_HEAP_TYPE_DEFAULT, &desc, initialState, &info->fAlloc, clearValue);
49cb93a386Sopenharmony_ci    if (!info->fResource) {
50cb93a386Sopenharmony_ci        return false;
51cb93a386Sopenharmony_ci    }
52cb93a386Sopenharmony_ci
53cb93a386Sopenharmony_ci    info->fResourceState = initialState;
54cb93a386Sopenharmony_ci    info->fFormat = desc.Format;
55cb93a386Sopenharmony_ci    info->fLevelCount = desc.MipLevels;
56cb93a386Sopenharmony_ci    info->fSampleCount = desc.SampleDesc.Count;
57cb93a386Sopenharmony_ci    info->fSampleQualityPattern = desc.SampleDesc.Quality;
58cb93a386Sopenharmony_ci    info->fProtected = isProtected;
59cb93a386Sopenharmony_ci
60cb93a386Sopenharmony_ci    return true;
61cb93a386Sopenharmony_ci}
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_cistd::pair<GrD3DTextureResourceInfo, sk_sp<GrD3DResourceState>> GrD3DTextureResource::CreateMSAA(
64cb93a386Sopenharmony_ci        GrD3DGpu* gpu, SkISize dimensions, int sampleCnt, const GrD3DTextureResourceInfo& info,
65cb93a386Sopenharmony_ci        SkColor4f clearColor) {
66cb93a386Sopenharmony_ci    GrD3DTextureResourceInfo msInfo;
67cb93a386Sopenharmony_ci    sk_sp<GrD3DResourceState> msState;
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_ci    // create msaa surface
70cb93a386Sopenharmony_ci    D3D12_RESOURCE_DESC msTextureDesc = {};
71cb93a386Sopenharmony_ci    msTextureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
72cb93a386Sopenharmony_ci    msTextureDesc.Alignment = 0;  // Default alignment (64KB)
73cb93a386Sopenharmony_ci    msTextureDesc.Width = dimensions.fWidth;
74cb93a386Sopenharmony_ci    msTextureDesc.Height = dimensions.fHeight;
75cb93a386Sopenharmony_ci    msTextureDesc.DepthOrArraySize = 1;
76cb93a386Sopenharmony_ci    msTextureDesc.MipLevels = 1;
77cb93a386Sopenharmony_ci    msTextureDesc.Format = info.fFormat;
78cb93a386Sopenharmony_ci    msTextureDesc.SampleDesc.Count = sampleCnt;
79cb93a386Sopenharmony_ci    msTextureDesc.SampleDesc.Quality = DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN;
80cb93a386Sopenharmony_ci    msTextureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;  // Use default for dxgi format
81cb93a386Sopenharmony_ci    msTextureDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
82cb93a386Sopenharmony_ci
83cb93a386Sopenharmony_ci    D3D12_CLEAR_VALUE clearValue = {};
84cb93a386Sopenharmony_ci    clearValue.Format = info.fFormat;
85cb93a386Sopenharmony_ci    clearValue.Color[0] = clearColor.fR;
86cb93a386Sopenharmony_ci    clearValue.Color[1] = clearColor.fG;
87cb93a386Sopenharmony_ci    clearValue.Color[2] = clearColor.fB;
88cb93a386Sopenharmony_ci    clearValue.Color[3] = clearColor.fA;
89cb93a386Sopenharmony_ci
90cb93a386Sopenharmony_ci    if (!InitTextureResourceInfo(gpu, msTextureDesc, D3D12_RESOURCE_STATE_RENDER_TARGET,
91cb93a386Sopenharmony_ci                                 info.fProtected, &clearValue, &msInfo)) {
92cb93a386Sopenharmony_ci        return {};
93cb93a386Sopenharmony_ci    }
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ci    msState.reset(new GrD3DResourceState(
96cb93a386Sopenharmony_ci            static_cast<D3D12_RESOURCE_STATES>(msInfo.fResourceState)));
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ci    return std::make_pair(msInfo, msState);
99cb93a386Sopenharmony_ci}
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ciGrD3DTextureResource::~GrD3DTextureResource() {
102cb93a386Sopenharmony_ci    // Should have been reset() before
103cb93a386Sopenharmony_ci    SkASSERT(!fResource);
104cb93a386Sopenharmony_ci    SkASSERT(!fInfo.fResource);
105cb93a386Sopenharmony_ci}
106cb93a386Sopenharmony_ci
107cb93a386Sopenharmony_civoid GrD3DTextureResource::prepareForPresent(GrD3DGpu* gpu) {
108cb93a386Sopenharmony_ci    this->setResourceState(gpu, D3D12_RESOURCE_STATE_PRESENT);
109cb93a386Sopenharmony_ci}
110cb93a386Sopenharmony_ci
111cb93a386Sopenharmony_civoid GrD3DTextureResource::releaseResource(GrD3DGpu* gpu) {
112cb93a386Sopenharmony_ci    // TODO: do we need to migrate resource state if we change queues?
113cb93a386Sopenharmony_ci    if (fResource) {
114cb93a386Sopenharmony_ci        fResource.reset();
115cb93a386Sopenharmony_ci    }
116cb93a386Sopenharmony_ci    fInfo.fResource.reset();
117cb93a386Sopenharmony_ci    fInfo.fAlloc.reset();
118cb93a386Sopenharmony_ci}
119cb93a386Sopenharmony_ci
120cb93a386Sopenharmony_civoid GrD3DTextureResource::setResourceRelease(sk_sp<GrRefCntedCallback> releaseHelper) {
121cb93a386Sopenharmony_ci    SkASSERT(fResource);
122cb93a386Sopenharmony_ci    // Forward the release proc on to GrD3DTextureResource::Resource
123cb93a386Sopenharmony_ci    fResource->setRelease(std::move(releaseHelper));
124cb93a386Sopenharmony_ci}
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_civoid GrD3DTextureResource::Resource::freeGPUData() const {
127cb93a386Sopenharmony_ci    this->invokeReleaseProc();
128cb93a386Sopenharmony_ci    fResource.reset();  // Release our ref to the resource
129cb93a386Sopenharmony_ci    fAlloc.reset(); // Release our ref to the allocation
130cb93a386Sopenharmony_ci}
131