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