• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/d3d/GrD3DBuffer.h"
9 
10 #include "src/gpu/d3d/GrD3DGpu.h"
11 #include "src/gpu/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 }
80 
GrD3DBuffer(GrD3DGpu * gpu,size_t size,GrGpuBufferType intendedType,GrAccessPattern accessPattern,gr_cp<ID3D12Resource> bufferResource,sk_sp<GrD3DAlloc> alloc,D3D12_RESOURCE_STATES resourceState)81 GrD3DBuffer::GrD3DBuffer(GrD3DGpu* gpu, size_t size, GrGpuBufferType intendedType,
82                          GrAccessPattern accessPattern, gr_cp<ID3D12Resource> bufferResource,
83                          sk_sp<GrD3DAlloc> alloc, D3D12_RESOURCE_STATES resourceState)
84     : INHERITED(gpu, size, intendedType, accessPattern)
85     , fResourceState(resourceState)
86     , fD3DResource(std::move(bufferResource))
87     , fAlloc(std::move(alloc)) {
88     this->registerWithCache(SkBudgeted::kYes);
89 
90     // TODO: persistently map UPLOAD resources?
91 
92     VALIDATE();
93 }
94 
setResourceState(const GrD3DGpu * gpu,D3D12_RESOURCE_STATES newResourceState)95 void GrD3DBuffer::setResourceState(const GrD3DGpu* gpu,
96                                    D3D12_RESOURCE_STATES newResourceState) {
97     if (newResourceState == fResourceState ||
98         // GENERIC_READ encapsulates a lot of different read states
99         (fResourceState == D3D12_RESOURCE_STATE_GENERIC_READ &&
100          SkToBool(newResourceState | fResourceState))) {
101         return;
102     }
103 
104     D3D12_RESOURCE_TRANSITION_BARRIER barrier = {};
105     barrier.pResource = this->d3dResource();
106     barrier.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
107     barrier.StateBefore = fResourceState;
108     barrier.StateAfter = newResourceState;
109 
110     gpu->addBufferResourceBarriers(this, 1, &barrier);
111 
112     fResourceState = newResourceState;
113 }
114 
releaseResource()115 void GrD3DBuffer::releaseResource() {
116     if (this->wasDestroyed()) {
117         return;
118     }
119 
120     if (fMapPtr) {
121         this->internalUnmap(this->size());
122         fMapPtr = nullptr;
123     }
124 
125     SkASSERT(fD3DResource);
126     SkASSERT(fAlloc);
127     fD3DResource.reset();
128     fAlloc.reset();
129 }
130 
onRelease()131 void GrD3DBuffer::onRelease() {
132     this->releaseResource();
133     this->INHERITED::onRelease();
134 }
135 
onAbandon()136 void GrD3DBuffer::onAbandon() {
137     this->releaseResource();
138     this->INHERITED::onAbandon();
139 }
140 
onMap()141 void GrD3DBuffer::onMap() {
142     this->internalMap(this->size());
143 }
144 
onUnmap()145 void GrD3DBuffer::onUnmap() {
146     this->internalUnmap(this->size());
147 }
148 
onUpdateData(const void * src,size_t size)149 bool GrD3DBuffer::onUpdateData(const void* src, size_t size) {
150     SkASSERT(src);
151     if (size > this->size()) {
152         return false;
153     }
154     if (!fD3DResource) {
155         return false;
156     }
157 
158     this->internalMap(size);
159     if (!fMapPtr) {
160         return false;
161     }
162     if (this->accessPattern() == kStatic_GrAccessPattern) {
163         // We should never call this method on static buffers in protected contexts.
164         SkASSERT(!this->getD3DGpu()->protectedContext());
165         //*** any alignment restrictions?
166     }
167     memcpy(fMapPtr, src, size);
168     this->internalUnmap(size);
169 
170     return true;
171 }
172 
internalMap(size_t size)173 void GrD3DBuffer::internalMap(size_t size) {
174     // TODO: if UPLOAD heap type, could be persistently mapped (i.e., this would be a no-op)
175     if (this->wasDestroyed()) {
176         return;
177     }
178     SkASSERT(fD3DResource);
179     SkASSERT(!this->isMapped());
180     SkASSERT(this->size() >= size);
181 
182     VALIDATE();
183 
184     if (this->accessPattern() == kStatic_GrAccessPattern) {
185         SkASSERT(!fStagingBuffer);
186         GrStagingBufferManager::Slice slice =
187                 this->getD3DGpu()->stagingBufferManager()->allocateStagingBufferSlice(size);
188         if (!slice.fBuffer) {
189             return;
190         }
191         fStagingBuffer = static_cast<const GrD3DBuffer*>(slice.fBuffer)->d3dResource();
192         fStagingOffset = slice.fOffset;
193         fMapPtr = slice.fOffsetMapPtr;
194     } else {
195         D3D12_RANGE range;
196         range.Begin = 0;
197         range.End = size;
198         fD3DResource->Map(0, &range, &fMapPtr);
199     }
200 
201     VALIDATE();
202 }
203 
internalUnmap(size_t size)204 void GrD3DBuffer::internalUnmap(size_t size) {
205     // TODO: if UPLOAD heap type, could be persistently mapped (i.e., this would be a no-op)
206     if (this->wasDestroyed()) {
207         return;
208     }
209     SkASSERT(fD3DResource);
210     SkASSERT(this->isMapped());
211     VALIDATE();
212 
213 #ifdef SK_BUILD_FOR_MAC
214     // In both cases the size needs to be 4-byte aligned on Mac
215     sizeInBytes = SkAlign4(sizeInBytes);
216 #endif
217     if (this->accessPattern() == kStatic_GrAccessPattern) {
218         SkASSERT(fStagingBuffer);
219         this->setResourceState(this->getD3DGpu(), D3D12_RESOURCE_STATE_COPY_DEST);
220         this->getD3DGpu()->currentCommandList()->copyBufferToBuffer(
221                 sk_ref_sp<GrD3DBuffer>(this), 0, fStagingBuffer, fStagingOffset, size);
222         fStagingBuffer = nullptr;
223     } else {
224         D3D12_RANGE range;
225         range.Begin = 0;
226         // For READBACK heaps, unmap requires an empty range
227         range.End = fResourceState == D3D12_RESOURCE_STATE_COPY_DEST ? 0 : size;
228         SkASSERT(this->size() >= size);
229         fD3DResource->Unmap(0, &range);
230     }
231 
232     fMapPtr = nullptr;
233 
234     VALIDATE();
235 }
236 
237 #ifdef SK_DEBUG
validate() const238 void GrD3DBuffer::validate() const {
239     SkASSERT(this->intendedType() == GrGpuBufferType::kVertex ||
240              this->intendedType() == GrGpuBufferType::kIndex ||
241              this->intendedType() == GrGpuBufferType::kDrawIndirect ||
242              this->intendedType() == GrGpuBufferType::kXferCpuToGpu ||
243              this->intendedType() == GrGpuBufferType::kXferGpuToCpu);
244 }
245 #endif
246