void FD3D12DynamicRHI::UnlockBuffer(FRHICommandListImmediate* RHICmdList, BufferType* Buffer) { // Find the outstanding lock for this Buffer. FD3D12LockedKey LockedKey(Buffer); FD3D12LockedData* LockedData = FindInOutstandingLocks(LockedKey); check(LockedData); // Determine whether the buffer is dynamic or not. const bool bIsDynamic = (Buffer->GetUsage() & BUF_AnyDynamic) ? true : false; if (bIsDynamic) { // If the Buffer is dynamic, its upload heap memory can always stay mapped. Don't do anything. } else { // If the static Buffer lock involved a staging resource, it was locked for reading. if (LockedData->StagingResource) { // Unmap the staging buffer's memory. ID3D12Resource* StagingBuffer = LockedData->StagingResource.GetReference()->GetResource(); StagingBuffer->Unmap(0, nullptr); } else { // Copy the contents of the temporary memory buffer allocated for writing into the Buffer. FD3D12ResourceLocation* UploadHeapLocation = LockedData->UploadHeapLocation.GetReference(); // If we are on the render thread, queue up the copy on the RHIThread so it happens at the correct time. if (ShouldDeferBufferLockOperation(RHICmdList)) { new (RHICmdList->AllocCommand<FRHICommandUpdateBuffer>()) FRHICommandUpdateBuffer(Buffer->ResourceLocation, UploadHeapLocation, LockedData->Pitch); } else { UpdateBuffer(Buffer->ResourceLocation->GetResource(), Buffer->ResourceLocation->GetOffset(), UploadHeapLocation->GetResource(), UploadHeapLocation->GetOffset(), LockedData->Pitch); } } } // Remove the FD3D12LockedData from the lock map. // If the lock involved a staging resource, this releases it. RemoveFromOutstandingLocks(LockedKey); }
void FD3D11DynamicRHI::RHIUnlockStructuredBuffer(FStructuredBufferRHIParamRef StructuredBufferRHI) { FD3D11StructuredBuffer* StructuredBuffer = ResourceCast(StructuredBufferRHI); // Determine whether the Structured buffer is dynamic or not. D3D11_BUFFER_DESC Desc; StructuredBuffer->Resource->GetDesc(&Desc); const bool bIsDynamic = (Desc.Usage == D3D11_USAGE_DYNAMIC); // Find the outstanding lock for this VB. FD3D11LockedKey LockedKey(StructuredBuffer->Resource); FD3D11LockedData* LockedData = OutstandingLocks.Find(LockedKey); check(LockedData); if(bIsDynamic) { // If the VB is dynamic, its memory was mapped directly; unmap it. Direct3DDeviceIMContext->Unmap(StructuredBuffer->Resource,0); } else { // If the static VB lock involved a staging resource, it was locked for reading. if(LockedData->StagingResource) { // Unmap the staging buffer's memory. ID3D11Buffer* StagingBuffer = (ID3D11Buffer*)LockedData->StagingResource.GetReference(); Direct3DDeviceIMContext->Unmap(StagingBuffer,0); } else { // Copy the contents of the temporary memory buffer allocated for writing into the VB. Direct3DDeviceIMContext->UpdateSubresource(StructuredBuffer->Resource,LockedKey.Subresource,NULL,LockedData->GetData(),LockedData->Pitch,0); // Check the copy is finished before freeing... Direct3DDeviceIMContext->Flush(); // Free the temporary memory buffer. LockedData->FreeData(); } } // Remove the FD3D11LockedData from the lock map. // If the lock involved a staging resource, this releases it. OutstandingLocks.Remove(LockedKey); }
void* FD3D11DynamicRHI::RHILockIndexBuffer(FIndexBufferRHIParamRef IndexBufferRHI,uint32 Offset,uint32 Size,EResourceLockMode LockMode) { FD3D11IndexBuffer* IndexBuffer = ResourceCast(IndexBufferRHI); // If this resource is bound to the device, unbind it ConditionalClearShaderResource(IndexBuffer); // Determine whether the index buffer is dynamic or not. D3D11_BUFFER_DESC Desc; IndexBuffer->Resource->GetDesc(&Desc); const bool bIsDynamic = (Desc.Usage == D3D11_USAGE_DYNAMIC); FD3D11LockedKey LockedKey(IndexBuffer->Resource); FD3D11LockedData LockedData; if(bIsDynamic) { check(LockMode == RLM_WriteOnly); // If the buffer is dynamic, map its memory for writing. D3D11_MAPPED_SUBRESOURCE MappedSubresource; VERIFYD3D11RESULT(Direct3DDeviceIMContext->Map(IndexBuffer->Resource,0,D3D11_MAP_WRITE_DISCARD,0,&MappedSubresource)); LockedData.SetData(MappedSubresource.pData); LockedData.Pitch = MappedSubresource.RowPitch; } else { if(LockMode == RLM_ReadOnly) { // If the static buffer is being locked for reading, create a staging buffer. D3D11_BUFFER_DESC StagingBufferDesc; ZeroMemory( &StagingBufferDesc, sizeof( D3D11_BUFFER_DESC ) ); StagingBufferDesc.ByteWidth = Size; StagingBufferDesc.Usage = D3D11_USAGE_STAGING; StagingBufferDesc.BindFlags = 0; StagingBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; StagingBufferDesc.MiscFlags = 0; TRefCountPtr<ID3D11Buffer> StagingIndexBuffer; VERIFYD3D11RESULT(Direct3DDevice->CreateBuffer(&StagingBufferDesc,NULL,StagingIndexBuffer.GetInitReference())); LockedData.StagingResource = StagingIndexBuffer; // Copy the contents of the index buffer to the staging buffer. Direct3DDeviceIMContext->CopyResource(StagingIndexBuffer,IndexBuffer->Resource); // Map the staging buffer's memory for reading. D3D11_MAPPED_SUBRESOURCE MappedSubresource; VERIFYD3D11RESULT(Direct3DDeviceIMContext->Map(StagingIndexBuffer,0,D3D11_MAP_READ,0,&MappedSubresource)); LockedData.SetData(MappedSubresource.pData); LockedData.Pitch = MappedSubresource.RowPitch; } else { // If the static buffer is being locked for writing, allocate memory for the contents to be written to. LockedData.AllocData(Desc.ByteWidth); LockedData.Pitch = Desc.ByteWidth; } } // Add the lock to the lock map. OutstandingLocks.Add(LockedKey,LockedData); // Return the offset pointer return (void*)((uint8*)LockedData.GetData() + Offset); }
void* FD3D12DynamicRHI::LockBuffer(FRHICommandListImmediate* RHICmdList, BufferType* Buffer, uint32 Offset, uint32 Size, EResourceLockMode LockMode) { FD3D12LockedData LockedData; // Determine whether the buffer is dynamic or not. const bool bIsDynamic = (Buffer->GetUsage() & BUF_AnyDynamic) ? true : false; void* Data = nullptr; if (bIsDynamic) { check(LockMode == RLM_WriteOnly); TRefCountPtr<FD3D12ResourceLocation> newLocation = new FD3D12ResourceLocation(GetRHIDevice()); // Allocate a new resource Data = GetRHIDevice()->GetDefaultUploadHeapAllocator().AllocUploadResource(Buffer->ResourceLocation->GetEffectiveBufferSize(), Buffer->BufferAlignment, newLocation); // If on the RenderThread, queue up a command on the RHIThread to rename this buffer at the correct time if (ShouldDeferBufferLockOperation(RHICmdList)) { new (RHICmdList->AllocCommand<FRHICommandRenameUploadBuffer<BufferType>>()) FRHICommandRenameUploadBuffer<BufferType>(Buffer, newLocation); } else { Buffer->Rename(newLocation); } } else { FD3D12Resource* pResource = Buffer->ResourceLocation->GetResource(); // Locking for read must occur immediately so we can't queue up the operations later. if (LockMode == RLM_ReadOnly) { // If the static buffer is being locked for reading, create a staging buffer. TRefCountPtr<FD3D12Resource> StagingBuffer; VERIFYD3D11RESULT(GetRHIDevice()->GetResourceHelper().CreateBuffer(D3D12_HEAP_TYPE_READBACK, Offset + Size, StagingBuffer.GetInitReference())); LockedData.StagingResource = StagingBuffer; // Copy the contents of the buffer to the staging buffer. { const auto& pfnCopyContents = [&]() { FD3D12CommandContext& DefaultContext = GetRHIDevice()->GetDefaultCommandContext(); FD3D12CommandListHandle& hCommandList = DefaultContext.CommandListHandle; FScopeResourceBarrier ScopeResourceBarrierSource(hCommandList, pResource, pResource->GetDefaultResourceState(), D3D12_RESOURCE_STATE_COPY_SOURCE, 0); // Don't need to transition upload heaps DefaultContext.numCopies++; hCommandList->CopyBufferRegion( StagingBuffer->GetResource(), 0, pResource->GetResource(), Offset, Size); DefaultContext.FlushCommands(true); }; if (ShouldDeferBufferLockOperation(RHICmdList)) { // Sync when in the render thread implementation check(IsInRHIThread() == false); RHICmdList->ImmediateFlush(EImmediateFlushType::FlushRHIThread); pfnCopyContents(); } else { check(IsInRHIThread()); pfnCopyContents(); } } // Map the staging buffer's memory for reading. VERIFYD3D11RESULT(StagingBuffer->GetResource()->Map(0, nullptr, &Data)); } else { // If the static buffer is being locked for writing, allocate memory for the contents to be written to. TRefCountPtr<FD3D12ResourceLocation> UploadBufferLocation = new FD3D12ResourceLocation(GetRHIDevice()); Data = GetRHIDevice()->GetDefaultFastAllocator().Allocate(Offset + Size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT, UploadBufferLocation); // Keep track of the underlying resource for the upload heap so it can be referenced during Unmap. LockedData.UploadHeapLocation = UploadBufferLocation; } } check(Data); // Add the lock to the lock map. LockedData.SetData(Data); LockedData.Pitch = Offset + Size; // Add the lock to the lock map. FD3D12LockedKey LockedKey(Buffer); AddToOutstandingLocks(LockedKey, LockedData); // Return the offset pointer return (void*)((uint8*)LockedData.GetData() + Offset); }