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