/* * 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/d3d/GrD3DCpuDescriptorManager.h" #include "src/gpu/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, 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 = 1; 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::Make( GrD3DGpu* gpu, D3D12_DESCRIPTOR_HEAP_TYPE type, unsigned int numDescriptors) { std::unique_ptr heap = GrD3DDescriptorHeap::Make(gpu, type, numDescriptors, D3D12_DESCRIPTOR_HEAP_FLAG_NONE); if (!heap) { return nullptr; } return std::unique_ptr(new Heap(heap, numDescriptors)); } GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::Heap::allocateCPUHandle() { SkBitSet::OptionalIndex freeBlock = fFreeBlocks.findFirst(); SkASSERT(freeBlock); 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 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 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); }