| /* |
| * Copyright 2020 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "src/gpu/ganesh/d3d/GrD3DCpuDescriptorManager.h" |
| |
| #include "src/gpu/ganesh/d3d/GrD3DGpu.h" |
| |
| GrD3DCpuDescriptorManager::GrD3DCpuDescriptorManager(GrD3DGpu* gpu) |
| : fRTVDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_RTV) |
| , fDSVDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_DSV) |
| , fShaderViewDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV) |
| , fSamplerDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER) {} |
| |
| GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::createRenderTargetView( |
| GrD3DGpu* gpu, ID3D12Resource* textureResource) { |
| const GrD3DDescriptorHeap::CPUHandle& descriptor = fRTVDescriptorPool.allocateHandle(gpu); |
| gpu->device()->CreateRenderTargetView(textureResource, nullptr, descriptor.fHandle); |
| return descriptor; |
| } |
| |
| void GrD3DCpuDescriptorManager::recycleRenderTargetView( |
| const GrD3DDescriptorHeap::CPUHandle& rtvDescriptor) { |
| fRTVDescriptorPool.releaseHandle(rtvDescriptor); |
| } |
| |
| GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::createDepthStencilView( |
| GrD3DGpu* gpu, ID3D12Resource* textureResource) { |
| const GrD3DDescriptorHeap::CPUHandle& descriptor = fDSVDescriptorPool.allocateHandle(gpu); |
| gpu->device()->CreateDepthStencilView(textureResource, nullptr, descriptor.fHandle); |
| return descriptor; |
| } |
| |
| void GrD3DCpuDescriptorManager::recycleDepthStencilView( |
| const GrD3DDescriptorHeap::CPUHandle& dsvDescriptor) { |
| fDSVDescriptorPool.releaseHandle(dsvDescriptor); |
| } |
| |
| GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::createConstantBufferView( |
| GrD3DGpu* gpu, ID3D12Resource* bufferResource, size_t offset, size_t size) { |
| const GrD3DDescriptorHeap::CPUHandle& descriptor = |
| fShaderViewDescriptorPool.allocateHandle(gpu); |
| D3D12_CONSTANT_BUFFER_VIEW_DESC desc = {}; |
| desc.BufferLocation = bufferResource->GetGPUVirtualAddress() + offset; |
| desc.SizeInBytes = size; |
| gpu->device()->CreateConstantBufferView(&desc, descriptor.fHandle); |
| return descriptor; |
| } |
| |
| GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::createShaderResourceView( |
| GrD3DGpu* gpu, ID3D12Resource* resource, |
| unsigned int mostDetailedMip, unsigned int mipLevels) { |
| const GrD3DDescriptorHeap::CPUHandle& descriptor = |
| fShaderViewDescriptorPool.allocateHandle(gpu); |
| // TODO: for 4:2:0 YUV formats we'll need to map two different views, one for Y and one for UV. |
| // For now map the entire resource. |
| D3D12_SHADER_RESOURCE_VIEW_DESC desc = {}; |
| desc.Format = resource->GetDesc().Format; |
| desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; |
| desc.Texture2D.MostDetailedMip = mostDetailedMip; |
| desc.Texture2D.MipLevels = mipLevels; |
| desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; |
| gpu->device()->CreateShaderResourceView(resource, &desc, descriptor.fHandle); |
| return descriptor; |
| } |
| |
| GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::createUnorderedAccessView( |
| GrD3DGpu* gpu, ID3D12Resource* resource, unsigned int mipSlice) { |
| const GrD3DDescriptorHeap::CPUHandle& descriptor = |
| fShaderViewDescriptorPool.allocateHandle(gpu); |
| if (resource->GetDesc().Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) { |
| // TODO: figure out buffer setup |
| gpu->device()->CreateUnorderedAccessView(resource, nullptr, nullptr, descriptor.fHandle); |
| } else { |
| D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {}; |
| desc.Format = resource->GetDesc().Format; |
| desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; |
| desc.Texture2D.MipSlice = mipSlice; |
| gpu->device()->CreateUnorderedAccessView(resource, nullptr, &desc, descriptor.fHandle); |
| } |
| return descriptor; |
| } |
| |
| void GrD3DCpuDescriptorManager::recycleShaderView( |
| const GrD3DDescriptorHeap::CPUHandle& view) { |
| fShaderViewDescriptorPool.releaseHandle(view); |
| } |
| |
| GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::createSampler( |
| GrD3DGpu* gpu, |
| D3D12_FILTER filter, |
| float maxLOD, |
| unsigned int maxAnisotropy, |
| D3D12_TEXTURE_ADDRESS_MODE addressModeU, |
| D3D12_TEXTURE_ADDRESS_MODE addressModeV) { |
| const GrD3DDescriptorHeap::CPUHandle& descriptor = fSamplerDescriptorPool.allocateHandle(gpu); |
| D3D12_SAMPLER_DESC desc = {}; |
| desc.Filter = filter; |
| desc.AddressU = addressModeU; |
| desc.AddressV = addressModeV; |
| desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; |
| desc.MipLODBias = 0; |
| desc.MaxAnisotropy = maxAnisotropy; |
| desc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS; |
| // desc.BorderColor initialized to { 0, 0, 0, 0 } by default initializer, above. |
| desc.MinLOD = 0; |
| desc.MaxLOD = maxLOD; |
| |
| gpu->device()->CreateSampler(&desc, descriptor.fHandle); |
| return descriptor; |
| } |
| |
| void GrD3DCpuDescriptorManager::recycleSampler( |
| const GrD3DDescriptorHeap::CPUHandle& samplerDescriptor) { |
| fSamplerDescriptorPool.releaseHandle(samplerDescriptor); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| std::unique_ptr<GrD3DCpuDescriptorManager::Heap> GrD3DCpuDescriptorManager::Heap::Make( |
| GrD3DGpu* gpu, D3D12_DESCRIPTOR_HEAP_TYPE type, unsigned int numDescriptors) { |
| std::unique_ptr<GrD3DDescriptorHeap> heap = |
| GrD3DDescriptorHeap::Make(gpu, type, numDescriptors, D3D12_DESCRIPTOR_HEAP_FLAG_NONE); |
| if (!heap) { |
| return nullptr; |
| } |
| |
| return std::unique_ptr<Heap>(new Heap(heap, numDescriptors)); |
| } |
| |
| GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::Heap::allocateCPUHandle() { |
| SkBitSet::OptionalIndex freeBlock = fFreeBlocks.findFirst(); |
| SkASSERT(freeBlock.has_value()); |
| fFreeBlocks.reset(*freeBlock); |
| --fFreeCount; |
| return fHeap->getCPUHandle(*freeBlock); |
| } |
| |
| void GrD3DCpuDescriptorManager::Heap::freeCPUHandle(const GrD3DDescriptorHeap::CPUHandle& handle) { |
| SkASSERT(this->ownsHandle(handle)); |
| size_t index = fHeap->getIndex(handle); |
| fFreeBlocks.set(index); |
| ++fFreeCount; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| GrD3DCpuDescriptorManager::HeapPool::HeapPool(GrD3DGpu* gpu, D3D12_DESCRIPTOR_HEAP_TYPE heapType) |
| : fMaxAvailableDescriptors(32) |
| , fHeapType(heapType) { |
| std::unique_ptr<GrD3DCpuDescriptorManager::Heap> heap = |
| GrD3DCpuDescriptorManager::Heap::Make(gpu, fHeapType, fMaxAvailableDescriptors); |
| fDescriptorHeaps.push_back(std::move(heap)); |
| } |
| |
| GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::HeapPool::allocateHandle( |
| GrD3DGpu* gpu) { |
| for (unsigned int i = 0; i < fDescriptorHeaps.size(); ++i) { |
| if (fDescriptorHeaps[i]->canAllocate()) { |
| GrD3DDescriptorHeap::CPUHandle handle = fDescriptorHeaps[i]->allocateCPUHandle(); |
| return handle; |
| } |
| } |
| |
| // need to allocate more space |
| std::unique_ptr<GrD3DCpuDescriptorManager::Heap> heap = |
| GrD3DCpuDescriptorManager::Heap::Make(gpu, fHeapType, fMaxAvailableDescriptors); |
| // TODO: handle failed heap creation and/or memory restrictions better |
| // skbug.com/11959 |
| SkASSERT(heap); |
| |
| fDescriptorHeaps.push_back(std::move(heap)); |
| fMaxAvailableDescriptors *= 2; |
| GrD3DDescriptorHeap::CPUHandle handle = |
| fDescriptorHeaps[fDescriptorHeaps.size() - 1]->allocateCPUHandle(); |
| return handle; |
| } |
| |
| void GrD3DCpuDescriptorManager::HeapPool::releaseHandle( |
| const GrD3DDescriptorHeap::CPUHandle& dsvDescriptor) { |
| for (unsigned int i = 0; i < fDescriptorHeaps.size(); ++i) { |
| if (fDescriptorHeaps[i]->ownsHandle(dsvDescriptor)) { |
| fDescriptorHeaps[i]->freeCPUHandle(dsvDescriptor); |
| return; |
| } |
| } |
| SkASSERT(false); |
| } |