int32 FAsyncIOSystemBase::CancelRequests( uint64* RequestIndices, int32 NumIndices ) { FScopeLock ScopeLock( CriticalSection ); // Iterate over all outstanding requests and cancel matching ones. int32 RequestsCanceled = 0; for( int32 OutstandingIndex=OutstandingRequests.Num()-1; OutstandingIndex>=0 && RequestsCanceled<NumIndices; OutstandingIndex-- ) { // Iterate over all indices of requests to cancel for( int32 TheRequestIndex=0; TheRequestIndex<NumIndices; TheRequestIndex++ ) { // Look for matching request index in queue. const FAsyncIORequest IORequest = OutstandingRequests[OutstandingIndex]; if( IORequest.RequestIndex == RequestIndices[TheRequestIndex] ) { INC_DWORD_STAT( STAT_AsyncIO_CanceledReadCount ); INC_DWORD_STAT_BY( STAT_AsyncIO_CanceledReadSize, IORequest.Size ); DEC_DWORD_STAT( STAT_AsyncIO_OutstandingReadCount ); DEC_DWORD_STAT_BY( STAT_AsyncIO_OutstandingReadSize, IORequest.Size ); // Decrement thread-safe counter to indicate that request has been "completed". IORequest.Counter->Decrement(); // IORequest variable no longer valid after removal. OutstandingRequests.RemoveAt( OutstandingIndex ); RequestsCanceled++; // Break out of loop as we've modified OutstandingRequests AND it no longer is valid. break; } } } return RequestsCanceled; }
FD3D12BoundShaderState::~FD3D12BoundShaderState() { DEC_DWORD_STAT(STAT_D3D12NumBoundShaderState); #if D3D12_SUPPORTS_PARALLEL_RHI_EXECUTE CacheLink.RemoveFromCache(); #endif }
SWidget::~SWidget() { // Unregister all ActiveTimers so they aren't left stranded in the Application's list. if ( FSlateApplicationBase::IsInitialized() ) { for ( const auto& ActiveTimerHandle : ActiveTimers ) { FSlateApplicationBase::Get().UnRegisterActiveTimer(ActiveTimerHandle); } } DEC_DWORD_STAT(STAT_SlateTotalWidgets); }
/** Does per-frame global updating for the uniform buffer pool. */ void UniformBufferBeginFrame() { int32 NumCleaned = 0; SCOPE_CYCLE_COUNTER(STAT_D3D11CleanUniformBufferTime); // Clean a limited number of old entries to reduce hitching when leaving a large level for (int32 BucketIndex = 0; BucketIndex < NumPoolBuckets; BucketIndex++) { for (int32 EntryIndex = UniformBufferPool[BucketIndex].Num() - 1; EntryIndex >= 0 && NumCleaned < 10; EntryIndex--) { FPooledUniformBuffer& PoolEntry = UniformBufferPool[BucketIndex][EntryIndex]; check(IsValidRef(PoolEntry.Buffer)); // Clean entries that are unlikely to be reused if (GFrameNumberRenderThread - PoolEntry.FrameFreed > 30) { DEC_DWORD_STAT(STAT_D3D11NumFreeUniformBuffers); DEC_MEMORY_STAT_BY(STAT_D3D11FreeUniformBufferMemory, PoolEntry.CreatedSize); NumCleaned++; UpdateBufferStats(PoolEntry.Buffer, false); UniformBufferPool[BucketIndex].RemoveAtSwap(EntryIndex); } } } // Index of the bucket that is now old enough to be reused const int32 SafeFrameIndex = GFrameNumberRenderThread % NumSafeFrames; // Merge the bucket into the free pool array for (int32 BucketIndex = 0; BucketIndex < NumPoolBuckets; BucketIndex++) { int32 LastNum = UniformBufferPool[BucketIndex].Num(); UniformBufferPool[BucketIndex].Append(SafeUniformBufferPools[SafeFrameIndex][BucketIndex]); #if DO_CHECK while (LastNum < UniformBufferPool[BucketIndex].Num()) { check(IsValidRef(UniformBufferPool[BucketIndex][LastNum].Buffer)); LastNum++; } #endif SafeUniformBufferPools[SafeFrameIndex][BucketIndex].Reset(); } }
void USignificanceManager::UnregisterObject(const UObject* Object) { DEC_DWORD_STAT(STAT_SignificanceManager_NumObjects); SCOPE_CYCLE_COUNTER(STAT_SignificanceManager_UnregisterObject); FManagedObjectInfo* ObjectInfo; if (ManagedObjects.RemoveAndCopyValue(Object, ObjectInfo)) { TArray<const FManagedObjectInfo*>& ObjectsWithTag = ManagedObjectsByTag.FindChecked(ObjectInfo->GetTag()); if (ObjectsWithTag.Num() == 1) { check(ObjectsWithTag[0] == ObjectInfo); ManagedObjectsByTag.Remove(ObjectInfo->GetTag()); } else { ObjectsWithTag.RemoveSingle(ObjectInfo); } delete ObjectInfo; } }
FD3D11BoundShaderState::~FD3D11BoundShaderState() { DEC_DWORD_STAT(STAT_D3D11NumBoundShaderState); }
void FAsyncIOSystemBase::Tick() { // Create file handles. { TArray<FString> FileNamesToCacheHandles; // Only enter critical section for copying existing array over. We don't operate on the // real array as creating file handles might take a while and we don't want to have other // threads stalling on submission of requests. { FScopeLock ScopeLock( CriticalSection ); for( int32 RequestIdx=0; RequestIdx<OutstandingRequests.Num(); RequestIdx++ ) { // Early outs avoid unnecessary work and string copies with implicit allocator churn. FAsyncIORequest& OutstandingRequest = OutstandingRequests[RequestIdx]; if( OutstandingRequest.bHasAlreadyRequestedHandleToBeCached == false && OutstandingRequest.bIsDestroyHandleRequest == false && FindCachedFileHandle( OutstandingRequest.FileNameHash ) == NULL ) { new(FileNamesToCacheHandles)FString(*OutstandingRequest.FileName); OutstandingRequest.bHasAlreadyRequestedHandleToBeCached = true; } } } // Create file handles for requests down the pipe. This is done here so we can later on // use the handles to figure out the sort keys. for( int32 FileNameIndex=0; FileNameIndex<FileNamesToCacheHandles.Num(); FileNameIndex++ ) { GetCachedFileHandle( FileNamesToCacheHandles[FileNameIndex] ); } } // Copy of request. FAsyncIORequest IORequest; bool bIsRequestPending = false; { FScopeLock ScopeLock( CriticalSection ); if( OutstandingRequests.Num() ) { // Gets next request index based on platform specific criteria like layout on disc. int32 TheRequestIndex = PlatformGetNextRequestIndex(); if( TheRequestIndex != INDEX_NONE ) { // We need to copy as we're going to remove it... IORequest = OutstandingRequests[ TheRequestIndex ]; // ...right here. // NOTE: this needs to be a Remove, not a RemoveSwap because the base implementation // of PlatformGetNextRequestIndex is a FIFO taking priority into account OutstandingRequests.RemoveAt( TheRequestIndex ); // We're busy. Updated inside scoped lock to ensure BlockTillAllRequestsFinished works correctly. BusyWithRequest.Increment(); bIsRequestPending = true; } } } // We only have work to do if there's a request pending. if( bIsRequestPending ) { // handle a destroy handle request from the queue if( IORequest.bIsDestroyHandleRequest ) { IFileHandle* FileHandle = FindCachedFileHandle( IORequest.FileNameHash ); if( FileHandle ) { // destroy and remove the handle delete FileHandle; NameHashToHandleMap.Remove(IORequest.FileNameHash); } } else { // Retrieve cached handle or create it if it wasn't cached. We purposefully don't look at currently // set value as it might be stale by now. IFileHandle* FileHandle = GetCachedFileHandle( IORequest.FileName ); if( FileHandle ) { if( IORequest.UncompressedSize ) { // Data is compressed on disc so we need to also decompress. FulfillCompressedRead( IORequest, FileHandle ); } else { // Read data after seeking. InternalRead( FileHandle, IORequest.Offset, IORequest.Size, IORequest.Dest ); } INC_DWORD_STAT( STAT_AsyncIO_FulfilledReadCount ); INC_DWORD_STAT_BY( STAT_AsyncIO_FulfilledReadSize, IORequest.Size ); } else { //@todo streaming: add warning once we have thread safe logging. } DEC_DWORD_STAT( STAT_AsyncIO_OutstandingReadCount ); DEC_DWORD_STAT_BY( STAT_AsyncIO_OutstandingReadSize, IORequest.Size ); } // Request fulfilled. if( IORequest.Counter ) { IORequest.Counter->Decrement(); } // We're done reading for now. BusyWithRequest.Decrement(); } else { if( !OutstandingRequests.Num() && FPlatformProcess::SupportsMultithreading() ) { // We're really out of requests now, wait till the calling thread signals further work OutstandingRequestsEvent->Wait(); } } }
FUniformBufferRHIRef FD3D11DynamicRHI::RHICreateUniformBuffer(const void* Contents,const FRHIUniformBufferLayout& Layout,EUniformBufferUsage Usage) { check(IsInRenderingThread()); FD3D11UniformBuffer* NewUniformBuffer = nullptr; const uint32 NumBytes = Layout.ConstantBufferSize; if (NumBytes > 0) { // Constant buffers must also be 16-byte aligned. check(Align(NumBytes,16) == NumBytes); check(Align(Contents,16) == Contents); check(NumBytes <= D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * 16); check(NumBytes < (1 << NumPoolBuckets)); SCOPE_CYCLE_COUNTER(STAT_D3D11UpdateUniformBufferTime); if (IsPoolingEnabled()) { TRefCountPtr<ID3D11Buffer> UniformBufferResource; FRingAllocation RingAllocation; if (!RingAllocation.IsValid()) { // Find the appropriate bucket based on size const uint32 BucketIndex = GetPoolBucketIndex(NumBytes); TArray<FPooledUniformBuffer>& PoolBucket = UniformBufferPool[BucketIndex]; if (PoolBucket.Num() > 0) { // Reuse the last entry in this size bucket FPooledUniformBuffer FreeBufferEntry = PoolBucket.Pop(); check(IsValidRef(FreeBufferEntry.Buffer)); UniformBufferResource = FreeBufferEntry.Buffer; checkf(FreeBufferEntry.CreatedSize >= NumBytes, TEXT("%u %u %u %u"), NumBytes, BucketIndex, FreeBufferEntry.CreatedSize, GetPoolBucketSize(NumBytes)); DEC_DWORD_STAT(STAT_D3D11NumFreeUniformBuffers); DEC_MEMORY_STAT_BY(STAT_D3D11FreeUniformBufferMemory, FreeBufferEntry.CreatedSize); } // Nothing usable was found in the free pool, create a new uniform buffer if (!IsValidRef(UniformBufferResource)) { D3D11_BUFFER_DESC Desc; // Allocate based on the bucket size, since this uniform buffer will be reused later Desc.ByteWidth = GetPoolBucketSize(NumBytes); // Use D3D11_USAGE_DYNAMIC, which allows multiple CPU writes for pool reuses // This is method of updating is vastly superior to creating a new constant buffer each time with D3D11_USAGE_IMMUTABLE, // Since that inserts the data into the command buffer which causes GPU flushes Desc.Usage = D3D11_USAGE_DYNAMIC; Desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; Desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; Desc.MiscFlags = 0; Desc.StructureByteStride = 0; VERIFYD3D11RESULT(Direct3DDevice->CreateBuffer(&Desc, NULL, UniformBufferResource.GetInitReference())); UpdateBufferStats(UniformBufferResource, true); } check(IsValidRef(UniformBufferResource)); D3D11_MAPPED_SUBRESOURCE MappedSubresource; // Discard previous results since we always do a full update VERIFYD3D11RESULT(Direct3DDeviceIMContext->Map(UniformBufferResource, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedSubresource)); check(MappedSubresource.RowPitch >= NumBytes); FMemory::Memcpy(MappedSubresource.pData, Contents, NumBytes); Direct3DDeviceIMContext->Unmap(UniformBufferResource, 0); } NewUniformBuffer = new FD3D11UniformBuffer(this, Layout, UniformBufferResource, RingAllocation); } else { // No pooling D3D11_BUFFER_DESC Desc; Desc.ByteWidth = NumBytes; Desc.Usage = D3D11_USAGE_IMMUTABLE; Desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; Desc.CPUAccessFlags = 0; Desc.MiscFlags = 0; Desc.StructureByteStride = 0; D3D11_SUBRESOURCE_DATA ImmutableData; ImmutableData.pSysMem = Contents; ImmutableData.SysMemPitch = ImmutableData.SysMemSlicePitch = 0; TRefCountPtr<ID3D11Buffer> UniformBufferResource; VERIFYD3D11RESULT(Direct3DDevice->CreateBuffer(&Desc,&ImmutableData,UniformBufferResource.GetInitReference())); NewUniformBuffer = new FD3D11UniformBuffer(this, Layout, UniformBufferResource, FRingAllocation()); } } else { // This uniform buffer contains no constants, only a resource table. NewUniformBuffer = new FD3D11UniformBuffer(this, Layout, nullptr, FRingAllocation()); } if (Layout.Resources.Num()) { int32 NumResources = Layout.Resources.Num(); FRHIResource** InResources = (FRHIResource**)((uint8*)Contents + Layout.ResourceOffset); NewUniformBuffer->ResourceTable.Empty(NumResources); NewUniformBuffer->ResourceTable.AddZeroed(NumResources); for (int32 i = 0; i < NumResources; ++i) { check(InResources[i]); NewUniformBuffer->ResourceTable[i] = InResources[i]; } NewUniformBuffer->RawResourceTable.Empty(NumResources); NewUniformBuffer->RawResourceTable.AddZeroed(NumResources); } return NewUniformBuffer; }