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/d3d/GrD3DBuffer.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "src/gpu/d3d/GrD3DGpu.h"
11cb93a386Sopenharmony_ci#include "src/gpu/d3d/GrD3DUtil.h"
12cb93a386Sopenharmony_ci
13cb93a386Sopenharmony_ci#ifdef SK_DEBUG
14cb93a386Sopenharmony_ci#define VALIDATE() this->validate()
15cb93a386Sopenharmony_ci#else
16cb93a386Sopenharmony_ci#define VALIDATE() do {} while(false)
17cb93a386Sopenharmony_ci#endif
18cb93a386Sopenharmony_ci
19cb93a386Sopenharmony_cistatic gr_cp<ID3D12Resource> make_d3d_buffer(GrD3DGpu* gpu,
20cb93a386Sopenharmony_ci                                             size_t size,
21cb93a386Sopenharmony_ci                                             GrGpuBufferType intendedType,
22cb93a386Sopenharmony_ci                                             GrAccessPattern accessPattern,
23cb93a386Sopenharmony_ci                                             D3D12_RESOURCE_STATES* resourceState,
24cb93a386Sopenharmony_ci                                             sk_sp<GrD3DAlloc>* alloc) {
25cb93a386Sopenharmony_ci    D3D12_HEAP_TYPE heapType;
26cb93a386Sopenharmony_ci    if (accessPattern == kStatic_GrAccessPattern) {
27cb93a386Sopenharmony_ci        SkASSERT(intendedType != GrGpuBufferType::kXferCpuToGpu &&
28cb93a386Sopenharmony_ci                 intendedType != GrGpuBufferType::kXferGpuToCpu);
29cb93a386Sopenharmony_ci        heapType = D3D12_HEAP_TYPE_DEFAULT;
30cb93a386Sopenharmony_ci        // Needs to be transitioned to appropriate state to be read in shader
31cb93a386Sopenharmony_ci        *resourceState = D3D12_RESOURCE_STATE_COPY_DEST;
32cb93a386Sopenharmony_ci    } else {
33cb93a386Sopenharmony_ci        if (intendedType == GrGpuBufferType::kXferGpuToCpu) {
34cb93a386Sopenharmony_ci            heapType = D3D12_HEAP_TYPE_READBACK;
35cb93a386Sopenharmony_ci            // Cannot be changed
36cb93a386Sopenharmony_ci            *resourceState = D3D12_RESOURCE_STATE_COPY_DEST;
37cb93a386Sopenharmony_ci        } else {
38cb93a386Sopenharmony_ci            heapType = D3D12_HEAP_TYPE_UPLOAD;
39cb93a386Sopenharmony_ci            // Cannot be changed
40cb93a386Sopenharmony_ci            // Includes VERTEX_AND_CONSTANT_BUFFER, INDEX_BUFFER, INDIRECT_ARGUMENT, and COPY_SOURCE
41cb93a386Sopenharmony_ci            *resourceState = D3D12_RESOURCE_STATE_GENERIC_READ;
42cb93a386Sopenharmony_ci        }
43cb93a386Sopenharmony_ci    }
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ci    D3D12_RESOURCE_DESC bufferDesc = {};
46cb93a386Sopenharmony_ci    bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
47cb93a386Sopenharmony_ci    bufferDesc.Alignment = 0;  // default alignment
48cb93a386Sopenharmony_ci    bufferDesc.Width = size;
49cb93a386Sopenharmony_ci    bufferDesc.Height = 1;
50cb93a386Sopenharmony_ci    bufferDesc.DepthOrArraySize = 1;
51cb93a386Sopenharmony_ci    bufferDesc.MipLevels = 1;
52cb93a386Sopenharmony_ci    bufferDesc.Format = DXGI_FORMAT_UNKNOWN;
53cb93a386Sopenharmony_ci    bufferDesc.SampleDesc.Count = 1;
54cb93a386Sopenharmony_ci    bufferDesc.SampleDesc.Quality = 0; // Doesn't apply to buffers
55cb93a386Sopenharmony_ci    bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
56cb93a386Sopenharmony_ci    bufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_ci    gr_cp<ID3D12Resource> resource = gpu->memoryAllocator()->createResource(
59cb93a386Sopenharmony_ci            heapType, &bufferDesc, *resourceState, alloc, nullptr);
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ci    return resource;
62cb93a386Sopenharmony_ci}
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_cisk_sp<GrD3DBuffer> GrD3DBuffer::Make(GrD3DGpu* gpu, size_t size, GrGpuBufferType intendedType,
65cb93a386Sopenharmony_ci                                     GrAccessPattern accessPattern) {
66cb93a386Sopenharmony_ci    SkASSERT(!gpu->protectedContext() || (accessPattern != kStatic_GrAccessPattern));
67cb93a386Sopenharmony_ci    D3D12_RESOURCE_STATES resourceState;
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_ci    sk_sp<GrD3DAlloc> alloc;
70cb93a386Sopenharmony_ci    gr_cp<ID3D12Resource> resource = make_d3d_buffer(gpu, size, intendedType, accessPattern,
71cb93a386Sopenharmony_ci                                                     &resourceState, &alloc);
72cb93a386Sopenharmony_ci    if (!resource) {
73cb93a386Sopenharmony_ci        return nullptr;
74cb93a386Sopenharmony_ci    }
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci    return sk_sp<GrD3DBuffer>(new GrD3DBuffer(gpu, size, intendedType, accessPattern,
77cb93a386Sopenharmony_ci                                              std::move(resource), std::move(alloc),
78cb93a386Sopenharmony_ci                                              resourceState));
79cb93a386Sopenharmony_ci}
80cb93a386Sopenharmony_ci
81cb93a386Sopenharmony_ciGrD3DBuffer::GrD3DBuffer(GrD3DGpu* gpu, size_t size, GrGpuBufferType intendedType,
82cb93a386Sopenharmony_ci                         GrAccessPattern accessPattern, gr_cp<ID3D12Resource> bufferResource,
83cb93a386Sopenharmony_ci                         sk_sp<GrD3DAlloc> alloc, D3D12_RESOURCE_STATES resourceState)
84cb93a386Sopenharmony_ci    : INHERITED(gpu, size, intendedType, accessPattern)
85cb93a386Sopenharmony_ci    , fResourceState(resourceState)
86cb93a386Sopenharmony_ci    , fD3DResource(std::move(bufferResource))
87cb93a386Sopenharmony_ci    , fAlloc(std::move(alloc)) {
88cb93a386Sopenharmony_ci    this->registerWithCache(SkBudgeted::kYes);
89cb93a386Sopenharmony_ci
90cb93a386Sopenharmony_ci    // TODO: persistently map UPLOAD resources?
91cb93a386Sopenharmony_ci
92cb93a386Sopenharmony_ci    VALIDATE();
93cb93a386Sopenharmony_ci}
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_civoid GrD3DBuffer::setResourceState(const GrD3DGpu* gpu,
96cb93a386Sopenharmony_ci                                   D3D12_RESOURCE_STATES newResourceState) {
97cb93a386Sopenharmony_ci    if (newResourceState == fResourceState ||
98cb93a386Sopenharmony_ci        // GENERIC_READ encapsulates a lot of different read states
99cb93a386Sopenharmony_ci        (fResourceState == D3D12_RESOURCE_STATE_GENERIC_READ &&
100cb93a386Sopenharmony_ci         SkToBool(newResourceState | fResourceState))) {
101cb93a386Sopenharmony_ci        return;
102cb93a386Sopenharmony_ci    }
103cb93a386Sopenharmony_ci
104cb93a386Sopenharmony_ci    D3D12_RESOURCE_TRANSITION_BARRIER barrier = {};
105cb93a386Sopenharmony_ci    barrier.pResource = this->d3dResource();
106cb93a386Sopenharmony_ci    barrier.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
107cb93a386Sopenharmony_ci    barrier.StateBefore = fResourceState;
108cb93a386Sopenharmony_ci    barrier.StateAfter = newResourceState;
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_ci    gpu->addBufferResourceBarriers(this, 1, &barrier);
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_ci    fResourceState = newResourceState;
113cb93a386Sopenharmony_ci}
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_civoid GrD3DBuffer::releaseResource() {
116cb93a386Sopenharmony_ci    if (this->wasDestroyed()) {
117cb93a386Sopenharmony_ci        return;
118cb93a386Sopenharmony_ci    }
119cb93a386Sopenharmony_ci
120cb93a386Sopenharmony_ci    if (fMapPtr) {
121cb93a386Sopenharmony_ci        this->internalUnmap(this->size());
122cb93a386Sopenharmony_ci        fMapPtr = nullptr;
123cb93a386Sopenharmony_ci    }
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ci    SkASSERT(fD3DResource);
126cb93a386Sopenharmony_ci    SkASSERT(fAlloc);
127cb93a386Sopenharmony_ci    fD3DResource.reset();
128cb93a386Sopenharmony_ci    fAlloc.reset();
129cb93a386Sopenharmony_ci}
130cb93a386Sopenharmony_ci
131cb93a386Sopenharmony_civoid GrD3DBuffer::onRelease() {
132cb93a386Sopenharmony_ci    this->releaseResource();
133cb93a386Sopenharmony_ci    this->INHERITED::onRelease();
134cb93a386Sopenharmony_ci}
135cb93a386Sopenharmony_ci
136cb93a386Sopenharmony_civoid GrD3DBuffer::onAbandon() {
137cb93a386Sopenharmony_ci    this->releaseResource();
138cb93a386Sopenharmony_ci    this->INHERITED::onAbandon();
139cb93a386Sopenharmony_ci}
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_civoid GrD3DBuffer::onMap() {
142cb93a386Sopenharmony_ci    this->internalMap(this->size());
143cb93a386Sopenharmony_ci}
144cb93a386Sopenharmony_ci
145cb93a386Sopenharmony_civoid GrD3DBuffer::onUnmap() {
146cb93a386Sopenharmony_ci    this->internalUnmap(this->size());
147cb93a386Sopenharmony_ci}
148cb93a386Sopenharmony_ci
149cb93a386Sopenharmony_cibool GrD3DBuffer::onUpdateData(const void* src, size_t size) {
150cb93a386Sopenharmony_ci    SkASSERT(src);
151cb93a386Sopenharmony_ci    if (size > this->size()) {
152cb93a386Sopenharmony_ci        return false;
153cb93a386Sopenharmony_ci    }
154cb93a386Sopenharmony_ci    if (!fD3DResource) {
155cb93a386Sopenharmony_ci        return false;
156cb93a386Sopenharmony_ci    }
157cb93a386Sopenharmony_ci
158cb93a386Sopenharmony_ci    this->internalMap(size);
159cb93a386Sopenharmony_ci    if (!fMapPtr) {
160cb93a386Sopenharmony_ci        return false;
161cb93a386Sopenharmony_ci    }
162cb93a386Sopenharmony_ci    if (this->accessPattern() == kStatic_GrAccessPattern) {
163cb93a386Sopenharmony_ci        // We should never call this method on static buffers in protected contexts.
164cb93a386Sopenharmony_ci        SkASSERT(!this->getD3DGpu()->protectedContext());
165cb93a386Sopenharmony_ci        //*** any alignment restrictions?
166cb93a386Sopenharmony_ci    }
167cb93a386Sopenharmony_ci    memcpy(fMapPtr, src, size);
168cb93a386Sopenharmony_ci    this->internalUnmap(size);
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_ci    return true;
171cb93a386Sopenharmony_ci}
172cb93a386Sopenharmony_ci
173cb93a386Sopenharmony_civoid GrD3DBuffer::internalMap(size_t size) {
174cb93a386Sopenharmony_ci    // TODO: if UPLOAD heap type, could be persistently mapped (i.e., this would be a no-op)
175cb93a386Sopenharmony_ci    if (this->wasDestroyed()) {
176cb93a386Sopenharmony_ci        return;
177cb93a386Sopenharmony_ci    }
178cb93a386Sopenharmony_ci    SkASSERT(fD3DResource);
179cb93a386Sopenharmony_ci    SkASSERT(!this->isMapped());
180cb93a386Sopenharmony_ci    SkASSERT(this->size() >= size);
181cb93a386Sopenharmony_ci
182cb93a386Sopenharmony_ci    VALIDATE();
183cb93a386Sopenharmony_ci
184cb93a386Sopenharmony_ci    if (this->accessPattern() == kStatic_GrAccessPattern) {
185cb93a386Sopenharmony_ci        SkASSERT(!fStagingBuffer);
186cb93a386Sopenharmony_ci        GrStagingBufferManager::Slice slice =
187cb93a386Sopenharmony_ci                this->getD3DGpu()->stagingBufferManager()->allocateStagingBufferSlice(size);
188cb93a386Sopenharmony_ci        if (!slice.fBuffer) {
189cb93a386Sopenharmony_ci            return;
190cb93a386Sopenharmony_ci        }
191cb93a386Sopenharmony_ci        fStagingBuffer = static_cast<const GrD3DBuffer*>(slice.fBuffer)->d3dResource();
192cb93a386Sopenharmony_ci        fStagingOffset = slice.fOffset;
193cb93a386Sopenharmony_ci        fMapPtr = slice.fOffsetMapPtr;
194cb93a386Sopenharmony_ci    } else {
195cb93a386Sopenharmony_ci        D3D12_RANGE range;
196cb93a386Sopenharmony_ci        range.Begin = 0;
197cb93a386Sopenharmony_ci        range.End = size;
198cb93a386Sopenharmony_ci        fD3DResource->Map(0, &range, &fMapPtr);
199cb93a386Sopenharmony_ci    }
200cb93a386Sopenharmony_ci
201cb93a386Sopenharmony_ci    VALIDATE();
202cb93a386Sopenharmony_ci}
203cb93a386Sopenharmony_ci
204cb93a386Sopenharmony_civoid GrD3DBuffer::internalUnmap(size_t size) {
205cb93a386Sopenharmony_ci    // TODO: if UPLOAD heap type, could be persistently mapped (i.e., this would be a no-op)
206cb93a386Sopenharmony_ci    if (this->wasDestroyed()) {
207cb93a386Sopenharmony_ci        return;
208cb93a386Sopenharmony_ci    }
209cb93a386Sopenharmony_ci    SkASSERT(fD3DResource);
210cb93a386Sopenharmony_ci    SkASSERT(this->isMapped());
211cb93a386Sopenharmony_ci    VALIDATE();
212cb93a386Sopenharmony_ci
213cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_MAC
214cb93a386Sopenharmony_ci    // In both cases the size needs to be 4-byte aligned on Mac
215cb93a386Sopenharmony_ci    sizeInBytes = SkAlign4(sizeInBytes);
216cb93a386Sopenharmony_ci#endif
217cb93a386Sopenharmony_ci    if (this->accessPattern() == kStatic_GrAccessPattern) {
218cb93a386Sopenharmony_ci        SkASSERT(fStagingBuffer);
219cb93a386Sopenharmony_ci        this->setResourceState(this->getD3DGpu(), D3D12_RESOURCE_STATE_COPY_DEST);
220cb93a386Sopenharmony_ci        this->getD3DGpu()->currentCommandList()->copyBufferToBuffer(
221cb93a386Sopenharmony_ci                sk_ref_sp<GrD3DBuffer>(this), 0, fStagingBuffer, fStagingOffset, size);
222cb93a386Sopenharmony_ci        fStagingBuffer = nullptr;
223cb93a386Sopenharmony_ci    } else {
224cb93a386Sopenharmony_ci        D3D12_RANGE range;
225cb93a386Sopenharmony_ci        range.Begin = 0;
226cb93a386Sopenharmony_ci        // For READBACK heaps, unmap requires an empty range
227cb93a386Sopenharmony_ci        range.End = fResourceState == D3D12_RESOURCE_STATE_COPY_DEST ? 0 : size;
228cb93a386Sopenharmony_ci        SkASSERT(this->size() >= size);
229cb93a386Sopenharmony_ci        fD3DResource->Unmap(0, &range);
230cb93a386Sopenharmony_ci    }
231cb93a386Sopenharmony_ci
232cb93a386Sopenharmony_ci    fMapPtr = nullptr;
233cb93a386Sopenharmony_ci
234cb93a386Sopenharmony_ci    VALIDATE();
235cb93a386Sopenharmony_ci}
236cb93a386Sopenharmony_ci
237cb93a386Sopenharmony_ci#ifdef SK_DEBUG
238cb93a386Sopenharmony_civoid GrD3DBuffer::validate() const {
239cb93a386Sopenharmony_ci    SkASSERT(this->intendedType() == GrGpuBufferType::kVertex ||
240cb93a386Sopenharmony_ci             this->intendedType() == GrGpuBufferType::kIndex ||
241cb93a386Sopenharmony_ci             this->intendedType() == GrGpuBufferType::kDrawIndirect ||
242cb93a386Sopenharmony_ci             this->intendedType() == GrGpuBufferType::kXferCpuToGpu ||
243cb93a386Sopenharmony_ci             this->intendedType() == GrGpuBufferType::kXferGpuToCpu);
244cb93a386Sopenharmony_ci}
245cb93a386Sopenharmony_ci#endif
246