xref: /aosp_15_r20/external/skia/src/gpu/ganesh/d3d/GrD3DBuffer.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2020 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/gpu/ganesh/d3d/GrD3DBuffer.h"
9 
10 #include "src/gpu/ganesh/d3d/GrD3DGpu.h"
11 #include "src/gpu/ganesh/d3d/GrD3DUtil.h"
12 
13 #ifdef SK_DEBUG
14 #define VALIDATE() this->validate()
15 #else
16 #define VALIDATE() do {} while(false)
17 #endif
18 
make_d3d_buffer(GrD3DGpu * gpu,size_t size,GrGpuBufferType intendedType,GrAccessPattern accessPattern,D3D12_RESOURCE_STATES * resourceState,sk_sp<GrD3DAlloc> * alloc)19 static gr_cp<ID3D12Resource> make_d3d_buffer(GrD3DGpu* gpu,
20                                              size_t size,
21                                              GrGpuBufferType intendedType,
22                                              GrAccessPattern accessPattern,
23                                              D3D12_RESOURCE_STATES* resourceState,
24                                              sk_sp<GrD3DAlloc>* alloc) {
25     D3D12_HEAP_TYPE heapType;
26     if (accessPattern == kStatic_GrAccessPattern) {
27         SkASSERT(intendedType != GrGpuBufferType::kXferCpuToGpu &&
28                  intendedType != GrGpuBufferType::kXferGpuToCpu);
29         heapType = D3D12_HEAP_TYPE_DEFAULT;
30         // Needs to be transitioned to appropriate state to be read in shader
31         *resourceState = D3D12_RESOURCE_STATE_COPY_DEST;
32     } else {
33         if (intendedType == GrGpuBufferType::kXferGpuToCpu) {
34             heapType = D3D12_HEAP_TYPE_READBACK;
35             // Cannot be changed
36             *resourceState = D3D12_RESOURCE_STATE_COPY_DEST;
37         } else {
38             heapType = D3D12_HEAP_TYPE_UPLOAD;
39             // Cannot be changed
40             // Includes VERTEX_AND_CONSTANT_BUFFER, INDEX_BUFFER, INDIRECT_ARGUMENT, and COPY_SOURCE
41             *resourceState = D3D12_RESOURCE_STATE_GENERIC_READ;
42         }
43     }
44 
45     D3D12_RESOURCE_DESC bufferDesc = {};
46     bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
47     bufferDesc.Alignment = 0;  // default alignment
48     bufferDesc.Width = size;
49     bufferDesc.Height = 1;
50     bufferDesc.DepthOrArraySize = 1;
51     bufferDesc.MipLevels = 1;
52     bufferDesc.Format = DXGI_FORMAT_UNKNOWN;
53     bufferDesc.SampleDesc.Count = 1;
54     bufferDesc.SampleDesc.Quality = 0; // Doesn't apply to buffers
55     bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
56     bufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
57 
58     gr_cp<ID3D12Resource> resource = gpu->memoryAllocator()->createResource(
59             heapType, &bufferDesc, *resourceState, alloc, nullptr);
60 
61     return resource;
62 }
63 
Make(GrD3DGpu * gpu,size_t size,GrGpuBufferType intendedType,GrAccessPattern accessPattern)64 sk_sp<GrD3DBuffer> GrD3DBuffer::Make(GrD3DGpu* gpu, size_t size, GrGpuBufferType intendedType,
65                                      GrAccessPattern accessPattern) {
66     SkASSERT(!gpu->protectedContext() || (accessPattern != kStatic_GrAccessPattern));
67     D3D12_RESOURCE_STATES resourceState;
68 
69     sk_sp<GrD3DAlloc> alloc;
70     gr_cp<ID3D12Resource> resource = make_d3d_buffer(gpu, size, intendedType, accessPattern,
71                                                      &resourceState, &alloc);
72     if (!resource) {
73         return nullptr;
74     }
75 
76     return sk_sp<GrD3DBuffer>(new GrD3DBuffer(gpu, size, intendedType, accessPattern,
77                                               std::move(resource), std::move(alloc),
78                                               resourceState,
79                                               /*label=*/"MakeD3DBuffer"));
80 }
81 
GrD3DBuffer(GrD3DGpu * gpu,size_t size,GrGpuBufferType intendedType,GrAccessPattern accessPattern,gr_cp<ID3D12Resource> bufferResource,sk_sp<GrD3DAlloc> alloc,D3D12_RESOURCE_STATES resourceState,std::string_view label)82 GrD3DBuffer::GrD3DBuffer(GrD3DGpu* gpu, size_t size, GrGpuBufferType intendedType,
83                          GrAccessPattern accessPattern, gr_cp<ID3D12Resource> bufferResource,
84                          sk_sp<GrD3DAlloc> alloc,
85                          D3D12_RESOURCE_STATES resourceState,
86                          std::string_view label)
87     : INHERITED(gpu, size, intendedType, accessPattern, label)
88     , fResourceState(resourceState)
89     , fD3DResource(std::move(bufferResource))
90     , fAlloc(std::move(alloc)) {
91     this->registerWithCache(skgpu::Budgeted::kYes);
92 
93     // TODO: persistently map UPLOAD resources?
94 
95     VALIDATE();
96 }
97 
setResourceState(const GrD3DGpu * gpu,D3D12_RESOURCE_STATES newResourceState)98 void GrD3DBuffer::setResourceState(const GrD3DGpu* gpu,
99                                    D3D12_RESOURCE_STATES newResourceState) {
100     if (newResourceState == fResourceState ||
101         // GENERIC_READ encapsulates a lot of different read states
102         (fResourceState == D3D12_RESOURCE_STATE_GENERIC_READ &&
103          SkToBool(newResourceState | fResourceState))) {
104         return;
105     }
106 
107     D3D12_RESOURCE_TRANSITION_BARRIER barrier = {};
108     barrier.pResource = this->d3dResource();
109     barrier.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
110     barrier.StateBefore = fResourceState;
111     barrier.StateAfter = newResourceState;
112 
113     gpu->addBufferResourceBarriers(this, 1, &barrier);
114 
115     fResourceState = newResourceState;
116 }
117 
releaseResource()118 void GrD3DBuffer::releaseResource() {
119     if (this->wasDestroyed()) {
120         return;
121     }
122 
123     if (fMapPtr) {
124         this->unmap();
125     }
126 
127     SkASSERT(fD3DResource);
128     SkASSERT(fAlloc);
129     fD3DResource.reset();
130     fAlloc.reset();
131 }
132 
onRelease()133 void GrD3DBuffer::onRelease() {
134     this->releaseResource();
135     this->INHERITED::onRelease();
136 }
137 
onAbandon()138 void GrD3DBuffer::onAbandon() {
139     this->releaseResource();
140     this->INHERITED::onAbandon();
141 }
142 
onMap(MapType type)143 void GrD3DBuffer::onMap(MapType type) {
144     fMapPtr = this->internalMap(type, 0, this->size());
145 }
146 
onUnmap(MapType type)147 void GrD3DBuffer::onUnmap(MapType type) {
148     this->internalUnmap(type, 0, this->size());
149 }
150 
onClearToZero()151 bool GrD3DBuffer::onClearToZero() {
152     if (!fD3DResource) {
153         return false;
154     }
155 
156     if (this->accessPattern() == kStatic_GrAccessPattern) {
157         GrStagingBufferManager::Slice slice =
158                 this->getD3DGpu()->stagingBufferManager()->allocateStagingBufferSlice(this->size());
159         if (!slice.fBuffer) {
160             return false;
161         }
162         std::memset(slice.fOffsetMapPtr, 0, this->size());
163         this->setResourceState(this->getD3DGpu(), D3D12_RESOURCE_STATE_COPY_DEST);
164         this->getD3DGpu()->currentCommandList()->copyBufferToBuffer(
165                 sk_ref_sp<GrD3DBuffer>(this),
166                 0,
167                 static_cast<const GrD3DBuffer*>(slice.fBuffer)->d3dResource(),
168                 slice.fOffset,
169                 this->size());
170         return true;
171     }
172 
173     void* ptr = this->internalMap(MapType::kWriteDiscard, 0, this->size());
174     if (!ptr) {
175         return false;
176     }
177     std::memset(ptr, 0, this->size());
178     this->internalUnmap(MapType::kWriteDiscard, 0, this->size());
179 
180     return true;
181 }
182 
onUpdateData(const void * src,size_t offset,size_t size,bool)183 bool GrD3DBuffer::onUpdateData(const void* src, size_t offset, size_t size, bool /*preserve*/) {
184     if (!fD3DResource) {
185         return false;
186     }
187 
188     void* ptr = this->internalMap(MapType::kWriteDiscard, offset, size);
189     if (!ptr) {
190         return false;
191     }
192     if (this->accessPattern() == kStatic_GrAccessPattern) {
193         // We should never call this method on static buffers in protected contexts.
194         SkASSERT(!this->getD3DGpu()->protectedContext());
195         //*** any alignment restrictions?
196     }
197     memcpy(ptr, src, size);
198     this->internalUnmap(MapType::kWriteDiscard, offset, size);
199 
200     return true;
201 }
202 
internalMap(MapType type,size_t offset,size_t size)203 void* GrD3DBuffer::internalMap(MapType type, size_t offset, size_t size) {
204     // TODO: if UPLOAD heap type, could be persistently mapped (i.e., this would be a no-op)
205     SkASSERT(fD3DResource);
206     SkASSERT(!this->isMapped());
207     SkASSERT(offset + size <= this->size());
208 
209     VALIDATE();
210 
211     if (this->accessPattern() == kStatic_GrAccessPattern) {
212         if (type == MapType::kRead) {
213             return nullptr;
214         }
215         SkASSERT(!fStagingBuffer);
216         GrStagingBufferManager::Slice slice =
217                 this->getD3DGpu()->stagingBufferManager()->allocateStagingBufferSlice(size);
218         if (!slice.fBuffer) {
219             return nullptr;
220         }
221         fStagingBuffer = static_cast<const GrD3DBuffer*>(slice.fBuffer)->d3dResource();
222         fStagingOffset = slice.fOffset;
223         VALIDATE();
224         return slice.fOffsetMapPtr;
225     }
226 
227     D3D12_RANGE range;
228     range.Begin = offset;
229     // The range passed here indicates the portion of the resource that may be
230     // read. If we're only writing then pass an empty range.
231     range.End = type == MapType::kRead ? offset + size : offset;
232     void* result;
233     if (fD3DResource->Map(0, &range, &result) != S_OK) {
234         return nullptr;
235     }
236     if (result) {
237         result = SkTAddOffset<void>(result, offset);
238     }
239     VALIDATE();
240     return result;
241 }
242 
internalUnmap(MapType type,size_t offset,size_t size)243 void GrD3DBuffer::internalUnmap(MapType type, size_t offset, size_t size) {
244     // TODO: if UPLOAD heap type, could be persistently mapped (i.e., this would be a no-op)
245     SkASSERT(fD3DResource);
246     SkASSERT(offset + size <= this->size());
247     VALIDATE();
248 
249     if (this->accessPattern() == kStatic_GrAccessPattern) {
250         SkASSERT(type != GrGpuBuffer::MapType::kRead);
251         SkASSERT(fStagingBuffer);
252         this->setResourceState(this->getD3DGpu(), D3D12_RESOURCE_STATE_COPY_DEST);
253         this->getD3DGpu()->currentCommandList()->copyBufferToBuffer(
254                 sk_ref_sp<GrD3DBuffer>(this),
255                 offset,
256                 fStagingBuffer,
257                 fStagingOffset,
258                 size);
259         fStagingBuffer = nullptr;
260     } else {
261         D3D12_RANGE range;
262         range.Begin = offset;
263         range.End = type == MapType::kWriteDiscard ? offset + size : offset;
264         // For READBACK heaps, unmap requires an empty range
265         SkASSERT(fResourceState != D3D12_RESOURCE_STATE_COPY_DEST || range.Begin == range.End);
266         fD3DResource->Unmap(0, &range);
267     }
268 
269     VALIDATE();
270 }
271 
onSetLabel()272 void GrD3DBuffer::onSetLabel() {
273     SkASSERT(fD3DResource);
274     if (!this->getLabel().empty()) {
275         const std::wstring label = L"_Skia_" + GrD3DMultiByteToWide(this->getLabel());
276         this->d3dResource()->SetName(label.c_str());
277     }
278 }
279 
280 #ifdef SK_DEBUG
validate() const281 void GrD3DBuffer::validate() const {
282     SkASSERT(this->intendedType() == GrGpuBufferType::kVertex ||
283              this->intendedType() == GrGpuBufferType::kIndex ||
284              this->intendedType() == GrGpuBufferType::kDrawIndirect ||
285              this->intendedType() == GrGpuBufferType::kXferCpuToGpu ||
286              this->intendedType() == GrGpuBufferType::kXferGpuToCpu);
287 }
288 #endif
289