FShaderResource::FShaderResource(const FShaderCompilerOutput& Output, FShaderType* InSpecificType) : SpecificType(InSpecificType) , NumInstructions(Output.NumInstructions) , NumTextureSamplers(Output.NumTextureSamplers) , NumRefs(0) , Canary(FShader::ShaderMagic_Initialized) { Target = Output.Target; // todo: can we avoid the memcpy? Code = Output.ShaderCode.GetReadAccess(); check(Code.Num() > 0); OutputHash = Output.OutputHash; checkSlow(OutputHash != FSHAHash()); { FScopeLock ShaderResourceIdMapLock(&ShaderResourceIdMapCritical); ShaderResourceIdMap.Add(GetId(), this); } INC_DWORD_STAT_BY_FName(GetMemoryStatType((EShaderFrequency)Target.Frequency).GetName(), Code.Num()); INC_DWORD_STAT_BY(STAT_Shaders_ShaderResourceMemory, GetSizeBytes()); INC_DWORD_STAT_BY(STAT_Shaders_NumShaderResourcesLoaded, 1); }
FSlateShaderResourceProxy* FSlateRHIResourceManager::GenerateTextureResource( const FNewTextureInfo& Info ) { FSlateShaderResourceProxy* NewProxy = NULL; const uint32 Width = Info.TextureData->GetWidth(); const uint32 Height = Info.TextureData->GetHeight(); if( Info.bShouldAtlas ) { const FAtlasedTextureSlot* NewSlot = NULL; FSlateTextureAtlasRHI* Atlas = NULL; // See if any atlases can hold the texture for( int32 AtlasIndex = 0; AtlasIndex < TextureAtlases.Num() && !NewSlot; ++AtlasIndex ) { Atlas = TextureAtlases[AtlasIndex]; NewSlot = Atlas->AddTexture( Width, Height, Info.TextureData->GetRawBytes() ); } if( !NewSlot ) { INC_DWORD_STAT_BY(STAT_SlateNumTextureAtlases, 1); Atlas = new FSlateTextureAtlasRHI( AtlasSize, AtlasSize, ESlateTextureAtlasPaddingStyle::DilateBorder ); TextureAtlases.Add( Atlas ); NewSlot = TextureAtlases.Last()->AddTexture( Width, Height, Info.TextureData->GetRawBytes() ); } check( Atlas && NewSlot ); // Create a proxy to the atlased texture. The texture being used is the atlas itself with sub uvs to access the correct texture NewProxy = new FSlateShaderResourceProxy; NewProxy->Resource = Atlas->GetAtlasTexture(); const uint32 Padding = NewSlot->Padding; NewProxy->StartUV = FVector2D((float)(NewSlot->X + Padding) / Atlas->GetWidth(), (float)(NewSlot->Y + Padding) / Atlas->GetHeight()); NewProxy->SizeUV = FVector2D( (float)(NewSlot->Width-Padding*2) / Atlas->GetWidth(), (float)(NewSlot->Height-Padding*2) / Atlas->GetHeight() ); NewProxy->ActualSize = FIntPoint( Width, Height ); } else { NewProxy = new FSlateShaderResourceProxy; // Create a new standalone texture because we can't atlas this one FSlateTexture2DRHIRef* Texture = new FSlateTexture2DRHIRef( Width, Height, PF_B8G8R8A8, Info.TextureData, Info.bSrgb ? TexCreate_SRGB : TexCreate_None ); // Add it to the list of non atlased textures that we must clean up later NonAtlasedTextures.Add( Texture ); INC_DWORD_STAT_BY( STAT_SlateNumNonAtlasedTextures, 1 ); BeginInitResource( Texture ); // The texture proxy only contains a single texture NewProxy->Resource = Texture; NewProxy->StartUV = FVector2D(0.0f, 0.0f); NewProxy->SizeUV = FVector2D(1.0f, 1.0f); NewProxy->ActualSize = FIntPoint( Width, Height ); } return NewProxy; }
void FShader::AddRef() { ++NumRefs; if (NumRefs == 1) { INC_DWORD_STAT_BY(STAT_Shaders_ShaderMemory, GetSizeBytes()); INC_DWORD_STAT_BY(STAT_Shaders_NumShadersLoaded,1); } }
FLoadedAudioChunk* FStreamingWaveData::AddNewLoadedChunk(int32 ChunkSize) { int32 NewIndex = LoadedChunks.Num(); LoadedChunks.AddZeroed(); LoadedChunks[NewIndex].Data = static_cast<uint8*>(FMemory::Malloc(ChunkSize)); LoadedChunks[NewIndex].DataSize = LoadedChunks[NewIndex].MemorySize = ChunkSize; INC_DWORD_STAT_BY(STAT_AudioMemorySize, ChunkSize); INC_DWORD_STAT_BY(STAT_AudioMemory, ChunkSize); return &LoadedChunks[NewIndex]; }
void FShader::AddRef() { check(Canary != ShaderMagic_CleaningUp); // Lock shader Id maps LockShaderIdMap(); ++NumRefs; if (NumRefs == 1) { INC_DWORD_STAT_BY(STAT_Shaders_ShaderMemory, GetSizeBytes()); INC_DWORD_STAT_BY(STAT_Shaders_NumShadersLoaded,1); } UnlockShaderIdMap(); }
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; }
FShaderResource::FShaderResource() : NumInstructions(0) , NumTextureSamplers(0) , NumRefs(0) { INC_DWORD_STAT_BY(STAT_Shaders_NumShaderResourcesLoaded, 1); }
//----------------------------------------------------------------------// // FNavigationOctree //----------------------------------------------------------------------// FNavigationOctree::FNavigationOctree(const FVector& Origin, float Radius) : TOctree<FNavigationOctreeElement, FNavigationOctreeSemantics>(Origin, Radius) , bGatherGeometry(false) , NodesMemory(0) { INC_DWORD_STAT_BY( STAT_NavigationMemory, sizeof(*this) ); }
void FShaderResource::Serialize(FArchive& Ar) { Ar << SpecificType; Ar << Target; Ar << Code; Ar << OutputHash; Ar << NumInstructions; Ar << NumTextureSamplers; if (Ar.IsLoading()) { INC_DWORD_STAT_BY_FName(GetMemoryStatType((EShaderFrequency)Target.Frequency).GetName(), (int64)Code.Num()); INC_DWORD_STAT_BY(STAT_Shaders_ShaderResourceMemory, GetSizeBytes()); FShaderCache::LogShader((EShaderPlatform)Target.Platform, (EShaderFrequency)Target.Frequency, OutputHash, Code); // The shader resource has been serialized in, so this shader resource is now initialized. check(Canary != FShader::ShaderMagic_CleaningUp); Canary = FShader::ShaderMagic_Initialized; } #if WITH_EDITORONLY_DATA else if(Ar.IsCooking()) { FShaderCache::CookShader((EShaderPlatform)Target.Platform, (EShaderFrequency)Target.Frequency, OutputHash, Code); } #endif }
//----------------------------------------------------------------------// // FNavigationOctree //----------------------------------------------------------------------// FNavigationOctree::FNavigationOctree(FVector Origin, float Radius) : Super(Origin, Radius) , bGatherGeometry(false) , NodesMemory(0) { INC_DWORD_STAT_BY( STAT_NavigationMemory, sizeof(*this) ); }
/** * Retrieves the dynamic data for the emitter * * @param bSelected Whether the emitter is selected in the editor * * @return FDynamicEmitterDataBase* The dynamic data, or NULL if it shouldn't be rendered */ FDynamicEmitterDataBase* FParticleBeam2EmitterInstance::GetDynamicData(bool bSelected) { QUICK_SCOPE_CYCLE_COUNTER(STAT_ParticleBeam2EmitterInstance_GetDynamicData); UParticleLODLevel* LODLevel = SpriteTemplate->GetCurrentLODLevel(this); if (IsDynamicDataRequired(LODLevel) == false) { return NULL; } //@todo.SAS. Have this call the UpdateDynamicData function to reduce duplicate code!!! //@SAS. This removes the need for the assertion in the actual render call... if ((ActiveParticles > FDynamicBeam2EmitterData::MaxBeams) || // TTP #33330 - Max of 2048 beams from a single emitter (ParticleStride > ((FDynamicBeam2EmitterData::MaxInterpolationPoints + 2) * (sizeof(FVector) + sizeof(float))) + (FDynamicBeam2EmitterData::MaxNoiseFrequency * (sizeof(FVector) + sizeof(FVector) + sizeof(float) + sizeof(float))) ) // TTP #33330 - Max of 10k per beam (includes interpolation points, noise, etc.) ) { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if (Component && Component->GetWorld()) { FString ErrorMessage = FString::Printf(TEXT("BeamEmitter with too much data: %s"), Component ? Component->Template ? *(Component->Template->GetName()) : TEXT("No template") : TEXT("No component")); FColor ErrorColor(255,0,0); GEngine->AddOnScreenDebugMessage((uint64)((PTRINT)this), 5.0f, ErrorColor,ErrorMessage); UE_LOG(LogParticles, Log, TEXT("%s"), *ErrorMessage); } #endif //#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) return NULL; } // Allocate the dynamic data FDynamicBeam2EmitterData* NewEmitterData = ::new FDynamicBeam2EmitterData(LODLevel->RequiredModule); { SCOPE_CYCLE_COUNTER(STAT_ParticleMemTime); INC_DWORD_STAT(STAT_DynamicEmitterCount); INC_DWORD_STAT(STAT_DynamicBeamCount); INC_DWORD_STAT_BY(STAT_DynamicEmitterMem, sizeof(FDynamicBeam2EmitterData)); } // Now fill in the source data if( !FillReplayData( NewEmitterData->Source ) ) { delete NewEmitterData; return NULL; } // Setup dynamic render data. Only call this AFTER filling in source data for the emitter. NewEmitterData->Init( bSelected ); return NewEmitterData; }
FShaderResource::FShaderResource() : SpecificType(NULL) , NumInstructions(0) , NumTextureSamplers(0) , NumRefs(0) , Canary(FShader::ShaderMagic_Uninitialized) { INC_DWORD_STAT_BY(STAT_Shaders_NumShaderResourcesLoaded, 1); }
FShaderResource::FShaderResource(const FShaderCompilerOutput& Output) : NumInstructions(Output.NumInstructions) , NumTextureSamplers(Output.NumTextureSamplers) , NumRefs(0) { Target = Output.Target; Code = Output.Code; check(Code.Num() > 0); OutputHash = Output.OutputHash; checkSlow(OutputHash != FSHAHash()); ShaderResourceIdMap.Add(GetId(), this); INC_DWORD_STAT_BY_FName(GetMemoryStatType((EShaderFrequency)Target.Frequency).GetName(), Code.Num()); INC_DWORD_STAT_BY(STAT_Shaders_ShaderResourceMemory, GetSizeBytes()); INC_DWORD_STAT_BY(STAT_Shaders_NumShaderResourcesLoaded, 1); }
uint64 FAsyncIOSystemBase::QueueIORequest( const FString& FileName, int64 Offset, int64 Size, int64 UncompressedSize, void* Dest, ECompressionFlags CompressionFlags, FThreadSafeCounter* Counter, EAsyncIOPriority Priority ) { check(Offset != INDEX_NONE); check(Dest != nullptr || Size == 0); FScopeLock ScopeLock(CriticalSection); // Create an IO request containing passed in information. FAsyncIORequest IORequest; IORequest.RequestIndex = RequestIndex++; IORequest.FileSortKey = INDEX_NONE; IORequest.FileName = FileName; IORequest.FileNameHash = FCrc::StrCrc32<TCHAR>(FileName.ToLower().GetCharArray().GetData()); IORequest.Offset = Offset; IORequest.Size = Size; IORequest.UncompressedSize = UncompressedSize; IORequest.Dest = Dest; IORequest.CompressionFlags = CompressionFlags; IORequest.Counter = Counter; IORequest.Priority = Priority; static bool HasCheckedCommandline = false; if (!HasCheckedCommandline) { HasCheckedCommandline = true; if ( FParse::Param(FCommandLine::Get(), TEXT("logasync"))) { GbLogAsyncLoading = true; UE_LOG(LogStreaming, Warning, TEXT("*** ASYNC LOGGING IS ENABLED")); } } if (GbLogAsyncLoading == true) { LogIORequest(TEXT("QueueIORequest"), IORequest); } INC_DWORD_STAT( STAT_AsyncIO_OutstandingReadCount ); INC_DWORD_STAT_BY( STAT_AsyncIO_OutstandingReadSize, IORequest.Size ); // Add to end of queue. OutstandingRequests.Add( IORequest ); // Trigger event telling IO thread to wake up to perform work. OutstandingRequestsEvent->Trigger(); // Return unique ID associated with request which can be used to cancel it. return IORequest.RequestIndex; }
void FNiagaraSimulation::Tick(float DeltaSeconds) { SCOPE_CYCLE_COUNTER(STAT_NiagaraTick); SimpleTimer TickTime; UNiagaraEmitterProperties* PinnedProps = Props.Get(); if (!PinnedProps || !bIsEnabled || TickState == NTS_Suspended || TickState == NTS_Dead) { return; } Age += DeltaSeconds; check(Data.GetNumVariables() > 0); check(PinnedProps->SpawnScriptProps.Script); check(PinnedProps->UpdateScriptProps.Script); TickEvents(DeltaSeconds); // Figure out how many we will spawn. int32 OrigNumParticles = Data.GetNumInstances(); int32 NumToSpawn = CalcNumToSpawn(DeltaSeconds); int32 MaxNewParticles = OrigNumParticles + NumToSpawn; Data.Allocate(MaxNewParticles); ExternalConstants.SetOrAdd(BUILTIN_CONST_EMITTERAGE, FVector4(Age, Age, Age, Age)); ExternalConstants.SetOrAdd(BUILTIN_CONST_DELTATIME, FVector4(DeltaSeconds, DeltaSeconds, DeltaSeconds, DeltaSeconds)); // Simulate particles forward by DeltaSeconds. if (TickState==NTS_Running || TickState==NTS_Dieing) { SCOPE_CYCLE_COUNTER(STAT_NiagaraSimulate); RunVMScript(PinnedProps->UpdateScriptProps, EUnusedAttributeBehaviour::PassThrough); } //Init new particles with the spawn script. if (TickState==NTS_Running) { SCOPE_CYCLE_COUNTER(STAT_NiagaraSpawn); Data.SetNumInstances(MaxNewParticles); //For now, zero any unused attributes here. But as this is really uninitialized data we should maybe make this a more serious error. RunVMScript(PinnedProps->SpawnScriptProps, EUnusedAttributeBehaviour::Zero, OrigNumParticles, NumToSpawn); if (bGenerateSpawnEvents) { SpawnEventGenerator.OnSpawned(OrigNumParticles, NumToSpawn); } } CPUTimeMS = TickTime.GetElapsedMilliseconds(); INC_DWORD_STAT_BY(STAT_NiagaraNumParticles, Data.GetNumInstances()); }
void UFontBulkData::Initialize(const void* const InFontData, const int32 InFontDataSizeBytes) { // The bulk data cannot be removed if we are loading a memory location since we // have no knowledge of this memory later BulkData.ClearBulkDataFlags( BULKDATA_SingleUse ); BulkData.Lock(LOCK_READ_WRITE); void* const LockedFontData = BulkData.Realloc(InFontDataSizeBytes); FMemory::Memcpy(LockedFontData, InFontData, InFontDataSizeBytes); BulkData.Unlock(); INC_DWORD_STAT_BY( STAT_SlateBulkFontDataMemory, BulkData.GetBulkDataSize() ); }
void FShaderResource::Serialize(FArchive& Ar) { Ar << Target; Ar << Code; Ar << OutputHash; Ar << NumInstructions; Ar << NumTextureSamplers; if (Ar.IsLoading()) { INC_DWORD_STAT_BY_FName(GetMemoryStatType((EShaderFrequency)Target.Frequency).GetName(), (int64)Code.Num()); INC_DWORD_STAT_BY(STAT_Shaders_ShaderResourceMemory, GetSizeBytes()); } }
void FShaderResource::InitRHI() { checkf(Code.Num() > 0, TEXT("FShaderResource::InitRHI was called with empty bytecode, which can happen if the resource is initialized multiple times on platforms with no editor data.")); // we can't have this called on the wrong platform's shaders if (!ArePlatformsCompatible(GMaxRHIShaderPlatform, (EShaderPlatform)Target.Platform)) { if (FPlatformProperties::RequiresCookedData()) { UE_LOG(LogShaders, Fatal, TEXT("FShaderResource::InitRHI got platform %s but it is not compatible with %s"), *LegacyShaderPlatformToShaderFormat((EShaderPlatform)Target.Platform).ToString(), *LegacyShaderPlatformToShaderFormat(GMaxRHIShaderPlatform).ToString()); } return; } INC_DWORD_STAT_BY(STAT_Shaders_NumShadersUsedForRendering, 1); SCOPE_CYCLE_COUNTER(STAT_Shaders_RTShaderLoadTime); if(Target.Frequency == SF_Vertex) { VertexShader = RHICreateVertexShader(Code); } else if(Target.Frequency == SF_Pixel) { PixelShader = RHICreatePixelShader(Code); } else if(Target.Frequency == SF_Hull) { HullShader = RHICreateHullShader(Code); } else if(Target.Frequency == SF_Domain) { DomainShader = RHICreateDomainShader(Code); } else if(Target.Frequency == SF_Geometry) { GeometryShader = RHICreateGeometryShader(Code); } else if(Target.Frequency == SF_Compute) { ComputeShader = RHICreateComputeShader(Code); } if (!FPlatformProperties::HasEditorOnlyData()) { DEC_DWORD_STAT_BY_FName(GetMemoryStatType((EShaderFrequency)Target.Frequency).GetName(), Code.Num()); DEC_DWORD_STAT_BY(STAT_Shaders_ShaderResourceMemory, Code.GetAllocatedSize()); Code.Empty(); } }
FArchive& operator<<(FArchive& Ar, FStaticShadowDepthMap& ShadowMap) { Ar << ShadowMap.WorldToLight; Ar << ShadowMap.ShadowMapSizeX; Ar << ShadowMap.ShadowMapSizeY; Ar << ShadowMap.DepthSamples; if (Ar.IsLoading()) { INC_DWORD_STAT_BY(STAT_PrecomputedShadowDepthMapMemory, ShadowMap.DepthSamples.GetAllocatedSize()); } return Ar; }
void FIndirectLightingCache::UpdateBlocks(FScene* Scene, FViewInfo* DebugDrawingView, TMap<FIntVector, FBlockUpdateInfo>& BlocksToUpdate) { if (BlocksToUpdate.Num() > 0 && !IsInitialized()) { InitResource(); } INC_DWORD_STAT_BY(STAT_IndirectLightingCacheUpdates, BlocksToUpdate.Num()); for (TMap<FIntVector, FBlockUpdateInfo>::TIterator It(BlocksToUpdate); It; ++It) { UpdateBlock(Scene, DebugDrawingView, It.Value()); } }
void UFontBulkData::Serialize(FArchive& Ar) { Super::Serialize(Ar); BulkData.Serialize(Ar, this); if( !GIsEditor && Ar.IsLoading() ) { BulkData.SetBulkDataFlags( BULKDATA_SingleUse ); } #if STATS if( Ar.IsLoading() && BulkData.IsBulkDataLoaded() ) { INC_DWORD_STAT_BY( STAT_SlateBulkFontDataMemory, BulkData.GetBulkDataSize() ); } #endif }
/** * Called when the resource is initialized. This is only called by the rendering thread. */ virtual void InitRHI() override { INC_DWORD_STAT_BY( STAT_TextureMemory, TextureSize ); INC_DWORD_STAT_FNAME_BY( LODGroupStatName, TextureSize ); // Create the RHI texture. uint32 TexCreateFlags = (Owner->SRGB ? TexCreate_SRGB : 0) | TexCreate_OfflineProcessed; FRHIResourceCreateInfo CreateInfo; TextureCubeRHI = RHICreateTextureCube( Owner->GetSizeX(), Owner->GetPixelFormat(), Owner->GetNumMips(), TexCreateFlags, CreateInfo ); TextureRHI = TextureCubeRHI; RHIBindDebugLabelName(TextureRHI, *Owner->GetName()); RHIUpdateTextureReference(Owner->TextureReference.TextureReferenceRHI,TextureRHI); // Read the mip-levels into the RHI texture. int32 NumMips = Owner->GetNumMips(); for( int32 FaceIndex=0; FaceIndex<6; FaceIndex++ ) { for(int32 MipIndex=0; MipIndex < NumMips; MipIndex++) { if( MipData[FaceIndex][MipIndex] != NULL ) { uint32 DestStride; void* TheMipData = RHILockTextureCubeFace( TextureCubeRHI, FaceIndex, 0, MipIndex, RLM_WriteOnly, DestStride, false ); GetData( FaceIndex, MipIndex, TheMipData, DestStride ); RHIUnlockTextureCubeFace( TextureCubeRHI, FaceIndex, 0, MipIndex, false ); } } } // Create the sampler state RHI resource. FSamplerStateInitializerRHI SamplerStateInitializer ( GSystemSettings.TextureLODSettings.GetSamplerFilter( Owner ), AM_Clamp, AM_Clamp, AM_Clamp ); SamplerStateRHI = RHICreateSamplerState(SamplerStateInitializer); // Set the greyscale format flag appropriately. EPixelFormat PixelFormat = Owner->GetPixelFormat(); bGreyScaleFormat = (PixelFormat == PF_G8) || (PixelFormat == PF_BC4); }
void UFontBulkData::Initialize(const FString& InFontFilename) { // The bulk data cannot be removed if we are loading from source file BulkData.ClearBulkDataFlags( BULKDATA_SingleUse ); TUniquePtr<FArchive> Reader(IFileManager::Get().CreateFileReader(*InFontFilename, 0)); if(Reader) { const int32 FontDataSizeBytes = Reader->TotalSize(); BulkData.Lock(LOCK_READ_WRITE); void* const LockedFontData = BulkData.Realloc(FontDataSizeBytes); Reader->Serialize(LockedFontData, FontDataSizeBytes); BulkData.Unlock(); INC_DWORD_STAT_BY( STAT_SlateBulkFontDataMemory, BulkData.GetBulkDataSize() ); } else { UE_LOG(LogSlate, Warning, TEXT("Failed to load font data from '%s'"), *InFontFilename); } }
void FOcclusionQueryBatcher::Flush(FRHICommandListImmediate& RHICmdList) { if(BatchOcclusionQueries.Num()) { FMemMark MemStackMark(FMemStack::Get()); // Create the indices for MaxBatchedPrimitives boxes. FIndexBufferRHIParamRef IndexBufferRHI = GOcclusionQueryIndexBuffer.IndexBufferRHI; // Draw the batches. for(int32 BatchIndex = 0, NumBatches = BatchOcclusionQueries.Num();BatchIndex < NumBatches;BatchIndex++) { FOcclusionBatch& Batch = BatchOcclusionQueries[BatchIndex]; FRenderQueryRHIParamRef BatchOcclusionQuery = Batch.Query; FVertexBufferRHIParamRef VertexBufferRHI = Batch.VertexAllocation.VertexBuffer->VertexBufferRHI; uint32 VertexBufferOffset = Batch.VertexAllocation.VertexOffset; const int32 NumPrimitivesThisBatch = (BatchIndex != (NumBatches-1)) ? MaxBatchedPrimitives : NumBatchedPrimitives; RHICmdList.BeginRenderQuery(BatchOcclusionQuery); RHICmdList.SetStreamSource(0, VertexBufferRHI, sizeof(FVector), VertexBufferOffset); RHICmdList.DrawIndexedPrimitive( IndexBufferRHI, PT_TriangleList, /*BaseVertexIndex=*/ 0, /*MinIndex=*/ 0, /*NumVertices=*/ 8 * NumPrimitivesThisBatch, /*StartIndex=*/ 0, /*NumPrimitives=*/ 12 * NumPrimitivesThisBatch, /*NumInstances=*/ 1 ); RHICmdList.EndRenderQuery(BatchOcclusionQuery); } INC_DWORD_STAT_BY(STAT_OcclusionQueries,BatchOcclusionQueries.Num()); // Reset the batch state. BatchOcclusionQueries.Empty(BatchOcclusionQueries.Num()); CurrentBatchOcclusionQuery = NULL; } }
const void* UFontBulkData::Lock(int32& OutFontDataSizeBytes) const { CriticalSection.Lock(); #if STATS bool bWasLoaded = BulkData.IsBulkDataLoaded(); #endif OutFontDataSizeBytes = BulkData.GetBulkDataSize(); const void* Data = BulkData.LockReadOnly(); #if STATS if( !bWasLoaded && BulkData.IsBulkDataLoaded() ) { INC_DWORD_STAT_BY( STAT_SlateBulkFontDataMemory, BulkData.GetBulkDataSize() ); } #endif return Data; }
void UFontBulkData::ForceLoadBulkData() { FScopeLock Lock(&CriticalSection); // Keep the bulk data resident once it's been loaded BulkData.ClearBulkDataFlags(BULKDATA_SingleUse); #if STATS const bool bWasLoaded = BulkData.IsBulkDataLoaded(); #endif // Trigger the load (if needed) BulkData.LockReadOnly(); BulkData.Unlock(); #if STATS if (!bWasLoaded && BulkData.IsBulkDataLoaded()) { INC_DWORD_STAT_BY(STAT_SlateBulkFontDataMemory, BulkData.GetBulkDataSize()); } #endif }
/** * Spawn particles for this instance * * @param OldLeftover The leftover time from the last spawn * @param Rate The rate at which particles should be spawned * @param DeltaTime The time slice to spawn over * @param Burst The number of burst particle * @param BurstTime The burst time addition (faked time slice) * * @return float The leftover fraction of spawning */ float FParticleBeam2EmitterInstance::SpawnBeamParticles(float OldLeftover, float Rate, float DeltaTime, int32 Burst, float BurstTime) { SCOPE_CYCLE_COUNTER(STAT_BeamSpawnTime); float SafetyLeftover = OldLeftover; float NewLeftover = OldLeftover + DeltaTime * Rate; // Ensure continous spawning... lots of fiddling. int32 Number = FMath::FloorToInt(NewLeftover); float Increment = 1.f / Rate; float StartTime = DeltaTime + OldLeftover * Increment - Increment; NewLeftover = NewLeftover - Number; // Always match the burst at a minimum if (Number < Burst) { Number = Burst; } // Account for burst time simulation if (BurstTime > KINDA_SMALL_NUMBER) { NewLeftover -= BurstTime / Burst; NewLeftover = FMath::Clamp<float>(NewLeftover, 0, NewLeftover); } // Force a beam bool bNoLivingParticles = false; if (ActiveParticles == 0) { bNoLivingParticles = true; if (Number == 0) Number = 1; } // Don't allow more than BeamCount beams... if (Number + ActiveParticles > BeamCount) { Number = BeamCount - ActiveParticles; } // Handle growing arrays. bool bProcessSpawn = true; int32 NewCount = ActiveParticles + Number; if (NewCount >= MaxActiveParticles) { if (DeltaTime < 0.25f) { bProcessSpawn = Resize(NewCount + FMath::TruncToInt(FMath::Sqrt((float)NewCount)) + 1); } else { bProcessSpawn = Resize((NewCount + FMath::TruncToInt(FMath::Sqrt((float)NewCount)) + 1), false); } } if (bProcessSpawn == true) { UParticleLODLevel* LODLevel = SpriteTemplate->GetCurrentLODLevel(this); check(LODLevel); // Spawn particles. SpawnParticles( Number, StartTime, Increment, Location, FVector::ZeroVector, NULL ); if (ForceSpawnCount > 0) { ForceSpawnCount = 0; } INC_DWORD_STAT_BY(STAT_BeamParticles, ActiveParticles); return NewLeftover; } INC_DWORD_STAT_BY(STAT_BeamParticles, ActiveParticles); return SafetyLeftover; }
void FShaderResource::InitRHI() { checkf(Code.Num() > 0, TEXT("FShaderResource::InitRHI was called with empty bytecode, which can happen if the resource is initialized multiple times on platforms with no editor data.")); // we can't have this called on the wrong platform's shaders if (!ArePlatformsCompatible(GMaxRHIShaderPlatform, (EShaderPlatform)Target.Platform)) { if (FPlatformProperties::RequiresCookedData()) { UE_LOG(LogShaders, Fatal, TEXT("FShaderResource::InitRHI got platform %s but it is not compatible with %s"), *LegacyShaderPlatformToShaderFormat((EShaderPlatform)Target.Platform).ToString(), *LegacyShaderPlatformToShaderFormat(GMaxRHIShaderPlatform).ToString()); } return; } INC_DWORD_STAT_BY(STAT_Shaders_NumShadersUsedForRendering, 1); SCOPE_CYCLE_COUNTER(STAT_Shaders_RTShaderLoadTime); FShaderCache* ShaderCache = FShaderCache::GetShaderCache(); if(Target.Frequency == SF_Vertex) { VertexShader = ShaderCache ? ShaderCache->GetVertexShader((EShaderPlatform)Target.Platform, OutputHash, Code) : RHICreateVertexShader(Code); } else if(Target.Frequency == SF_Pixel) { PixelShader = ShaderCache ? ShaderCache->GetPixelShader((EShaderPlatform)Target.Platform, OutputHash, Code) : RHICreatePixelShader(Code); } else if(Target.Frequency == SF_Hull) { HullShader = ShaderCache ? ShaderCache->GetHullShader((EShaderPlatform)Target.Platform, OutputHash, Code) : RHICreateHullShader(Code); } else if(Target.Frequency == SF_Domain) { DomainShader = ShaderCache ? ShaderCache->GetDomainShader((EShaderPlatform)Target.Platform, OutputHash, Code) : RHICreateDomainShader(Code); } else if(Target.Frequency == SF_Geometry) { if (SpecificType) { FStreamOutElementList ElementList; TArray<uint32> StreamStrides; int32 RasterizedStream = -1; SpecificType->GetStreamOutElements(ElementList, StreamStrides, RasterizedStream); checkf(ElementList.Num(), *FString::Printf(TEXT("Shader type %s was given GetStreamOutElements implementation that had no elements!"), SpecificType->GetName())); //@todo - not using the cache GeometryShader = RHICreateGeometryShaderWithStreamOutput(Code, ElementList, StreamStrides.Num(), StreamStrides.GetData(), RasterizedStream); } else { GeometryShader = ShaderCache ? ShaderCache->GetGeometryShader((EShaderPlatform)Target.Platform, OutputHash, Code) : RHICreateGeometryShader(Code); } } else if(Target.Frequency == SF_Compute) { ComputeShader = ShaderCache ? ShaderCache->GetComputeShader((EShaderPlatform)Target.Platform, Code) : RHICreateComputeShader(Code); } if (Target.Frequency != SF_Geometry) { checkf(!SpecificType, *FString::Printf(TEXT("Only geometry shaders can use GetStreamOutElements, shader type %s"), SpecificType->GetName())); } if (!FPlatformProperties::HasEditorOnlyData()) { DEC_DWORD_STAT_BY_FName(GetMemoryStatType((EShaderFrequency)Target.Frequency).GetName(), Code.Num()); DEC_DWORD_STAT_BY(STAT_Shaders_ShaderResourceMemory, Code.GetAllocatedSize()); Code.Empty(); } }
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(); } } }
void FRCPassPostProcessDeferredDecals::Process(FRenderingCompositePassContext& Context) { FRHICommandListImmediate& RHICmdList = Context.RHICmdList; FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); const bool bShaderComplexity = Context.View.Family->EngineShowFlags.ShaderComplexity; const bool bDBuffer = IsDBufferEnabled(); const bool bStencilSizeThreshold = CVarStencilSizeThreshold.GetValueOnRenderThread() >= 0; SCOPED_DRAW_EVENTF(RHICmdList, DeferredDecals, TEXT("DeferredDecals %s"), GetStageName(CurrentStage)); if (CurrentStage == DRS_BeforeBasePass) { // before BasePass, only if DBuffer is enabled check(bDBuffer); FPooledRenderTargetDesc GBufferADesc; SceneContext.GetGBufferADesc(GBufferADesc); // DBuffer: Decal buffer FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(GBufferADesc.Extent, PF_B8G8R8A8, FClearValueBinding::None, TexCreate_None, TexCreate_ShaderResource | TexCreate_RenderTargetable, false, 1, true, true)); if (!SceneContext.DBufferA) { Desc.ClearValue = FClearValueBinding::Black; GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SceneContext.DBufferA, TEXT("DBufferA")); } if (!SceneContext.DBufferB) { Desc.ClearValue = FClearValueBinding(FLinearColor(128.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f, 1)); GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SceneContext.DBufferB, TEXT("DBufferB")); } Desc.Format = PF_R8G8; if (!SceneContext.DBufferC) { Desc.ClearValue = FClearValueBinding(FLinearColor(0, 1, 0, 1)); GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SceneContext.DBufferC, TEXT("DBufferC")); } // we assume views are non overlapping, then we need to clear only once in the beginning, otherwise we would need to set scissor rects // and don't get FastClear any more. bool bFirstView = Context.View.Family->Views[0] == &Context.View; if (bFirstView) { SCOPED_DRAW_EVENT(RHICmdList, DBufferClear); FRHIRenderTargetView RenderTargets[3]; RenderTargets[0] = FRHIRenderTargetView(SceneContext.DBufferA->GetRenderTargetItem().TargetableTexture, 0, -1, ERenderTargetLoadAction::EClear, ERenderTargetStoreAction::EStore); RenderTargets[1] = FRHIRenderTargetView(SceneContext.DBufferB->GetRenderTargetItem().TargetableTexture, 0, -1, ERenderTargetLoadAction::EClear, ERenderTargetStoreAction::EStore); RenderTargets[2] = FRHIRenderTargetView(SceneContext.DBufferC->GetRenderTargetItem().TargetableTexture, 0, -1, ERenderTargetLoadAction::EClear, ERenderTargetStoreAction::EStore); FRHIDepthRenderTargetView DepthView(SceneContext.GetSceneDepthTexture(), ERenderTargetLoadAction::ELoad, ERenderTargetStoreAction::ENoAction, ERenderTargetLoadAction::ELoad, ERenderTargetStoreAction::ENoAction, FExclusiveDepthStencil(FExclusiveDepthStencil::DepthRead_StencilWrite)); FRHISetRenderTargetsInfo Info(3, RenderTargets, DepthView); RHICmdList.SetRenderTargetsAndClear(Info); } } // this cast is safe as only the dedicated server implements this differently and this pass should not be executed on the dedicated server const FViewInfo& View = Context.View; const FSceneViewFamily& ViewFamily = *(View.Family); bool bHasValidDBufferMask = false; if(ViewFamily.EngineShowFlags.Decals) { if(CurrentStage == DRS_BeforeBasePass || CurrentStage == DRS_BeforeLighting) { RenderMeshDecals(Context, CurrentStage); } FScene& Scene = *(FScene*)ViewFamily.Scene; //don't early return. Resolves must be run for fast clears to work. if (Scene.Decals.Num()) { FDecalRenderTargetManager RenderTargetManager(RHICmdList, Context.GetShaderPlatform(), CurrentStage); // Build a list of decals that need to be rendered for this view FTransientDecalRenderDataList SortedDecals; FDecalRendering::BuildVisibleDecalList(Scene, View, CurrentStage, SortedDecals); if (SortedDecals.Num() > 0) { SCOPED_DRAW_EVENTF(RHICmdList, DeferredDecalsInner, TEXT("DeferredDecalsInner %d/%d"), SortedDecals.Num(), Scene.Decals.Num()); // optimization to have less state changes EDecalRasterizerState LastDecalRasterizerState = DRS_Undefined; FDecalDepthState LastDecalDepthState; int32 LastDecalBlendMode = -1; int32 LastDecalHasNormal = -1; // Decal state can change based on its normal property.(SM5) FDecalRenderingCommon::ERenderTargetMode LastRenderTargetMode = FDecalRenderingCommon::RTM_Unknown; const ERHIFeatureLevel::Type SMFeatureLevel = Context.GetFeatureLevel(); SCOPED_DRAW_EVENT(RHICmdList, Decals); INC_DWORD_STAT_BY(STAT_Decals, SortedDecals.Num()); for (int32 DecalIndex = 0, DecalCount = SortedDecals.Num(); DecalIndex < DecalCount; DecalIndex++) { const FTransientDecalRenderData& DecalData = SortedDecals[DecalIndex]; const FDeferredDecalProxy& DecalProxy = *DecalData.DecalProxy; const FMatrix ComponentToWorldMatrix = DecalProxy.ComponentTrans.ToMatrixWithScale(); const FMatrix FrustumComponentToClip = FDecalRendering::ComputeComponentToClipMatrix(View, ComponentToWorldMatrix); EDecalBlendMode DecalBlendMode = DecalData.DecalBlendMode; EDecalRenderStage LocalDecalStage = FDecalRenderingCommon::ComputeRenderStage(View.GetShaderPlatform(), DecalBlendMode); bool bStencilThisDecal = IsStencilOptimizationAvailable(LocalDecalStage); FDecalRenderingCommon::ERenderTargetMode CurrentRenderTargetMode = FDecalRenderingCommon::ComputeRenderTargetMode(View.GetShaderPlatform(), DecalBlendMode, DecalData.bHasNormal); if (bShaderComplexity) { CurrentRenderTargetMode = FDecalRenderingCommon::RTM_SceneColor; // we want additive blending for the ShaderComplexity mode DecalBlendMode = DBM_Emissive; } // Here we assume that GBuffer can only be WorldNormal since it is the only GBufferTarget handled correctly. if (RenderTargetManager.bGufferADirty && DecalData.MaterialResource->NeedsGBuffer()) { RHICmdList.CopyToResolveTarget(SceneContext.GBufferA->GetRenderTargetItem().TargetableTexture, SceneContext.GBufferA->GetRenderTargetItem().TargetableTexture, true, FResolveParams()); RenderTargetManager.TargetsToResolve[FDecalRenderTargetManager::GBufferAIndex] = nullptr; RenderTargetManager.bGufferADirty = false; } // fewer rendertarget switches if possible if (CurrentRenderTargetMode != LastRenderTargetMode) { LastRenderTargetMode = CurrentRenderTargetMode; RenderTargetManager.SetRenderTargetMode(CurrentRenderTargetMode, DecalData.bHasNormal); Context.SetViewportAndCallRHI(Context.View.ViewRect); } bool bThisDecalUsesStencil = false; if (bStencilThisDecal && bStencilSizeThreshold) { // note this is after a SetStreamSource (in if CurrentRenderTargetMode != LastRenderTargetMode) call as it needs to get the VB input bThisDecalUsesStencil = RenderPreStencil(Context, ComponentToWorldMatrix, FrustumComponentToClip); LastDecalRasterizerState = DRS_Undefined; LastDecalDepthState = FDecalDepthState(); LastDecalBlendMode = -1; } const bool bBlendStateChange = DecalBlendMode != LastDecalBlendMode;// Has decal mode changed. const bool bDecalNormalChanged = GSupportsSeparateRenderTargetBlendState && // has normal changed for SM5 stain/translucent decals? (DecalBlendMode == DBM_Translucent || DecalBlendMode == DBM_Stain) && (int32)DecalData.bHasNormal != LastDecalHasNormal; // fewer blend state changes if possible if (bBlendStateChange || bDecalNormalChanged) { LastDecalBlendMode = DecalBlendMode; LastDecalHasNormal = (int32)DecalData.bHasNormal; SetDecalBlendState(RHICmdList, SMFeatureLevel, CurrentStage, (EDecalBlendMode)LastDecalBlendMode, DecalData.bHasNormal); } // todo const float ConservativeRadius = DecalData.ConservativeRadius; // const int32 IsInsideDecal = ((FVector)View.ViewMatrices.ViewOrigin - ComponentToWorldMatrix.GetOrigin()).SizeSquared() < FMath::Square(ConservativeRadius * 1.05f + View.NearClippingDistance * 2.0f) + ( bThisDecalUsesStencil ) ? 2 : 0; const bool bInsideDecal = ((FVector)View.ViewMatrices.ViewOrigin - ComponentToWorldMatrix.GetOrigin()).SizeSquared() < FMath::Square(ConservativeRadius * 1.05f + View.NearClippingDistance * 2.0f); // const bool bInsideDecal = !(IsInsideDecal & 1); // update rasterizer state if needed { bool bReverseHanded = false; { // Account for the reversal of handedness caused by negative scale on the decal const auto& Scale3d = DecalProxy.ComponentTrans.GetScale3D(); bReverseHanded = Scale3d[0] * Scale3d[1] * Scale3d[2] < 0.f; } EDecalRasterizerState DecalRasterizerState = ComputeDecalRasterizerState(bInsideDecal, bReverseHanded, View); if (LastDecalRasterizerState != DecalRasterizerState) { LastDecalRasterizerState = DecalRasterizerState; SetDecalRasterizerState(DecalRasterizerState, RHICmdList); } } // update DepthStencil state if needed { FDecalDepthState DecalDepthState = ComputeDecalDepthState(LocalDecalStage, bInsideDecal, bThisDecalUsesStencil); if (LastDecalDepthState != DecalDepthState) { LastDecalDepthState = DecalDepthState; SetDecalDepthState(DecalDepthState, RHICmdList); } } FDecalRendering::SetShader(RHICmdList, View, DecalData, FrustumComponentToClip); RHICmdList.DrawIndexedPrimitive(GetUnitCubeIndexBuffer(), PT_TriangleList, 0, 0, 8, 0, ARRAY_COUNT(GCubeIndices) / 3, 1); RenderTargetManager.bGufferADirty |= (RenderTargetManager.TargetsToResolve[FDecalRenderTargetManager::GBufferAIndex] != nullptr); } // we don't modify stencil but if out input was having stencil for us (after base pass - we need to clear) // Clear stencil to 0, which is the assumed default by other passes RHICmdList.Clear(false, FLinearColor::White, false, (float)ERHIZBuffer::FarPlane, true, 0, FIntRect()); } if (CurrentStage == DRS_BeforeBasePass) { // combine DBuffer RTWriteMasks; will end up in one texture we can load from in the base pass PS and decide whether to do the actual work or not RenderTargetManager.FlushMetaData(); if (GSupportsRenderTargetWriteMask) { DecodeRTWriteMask(Context); bHasValidDBufferMask = true; } } RenderTargetManager.ResolveTargets(); } if (CurrentStage == DRS_BeforeBasePass) { // before BasePass GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.DBufferA); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.DBufferB); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.DBufferC); } } if (CurrentStage == DRS_BeforeBasePass && !bHasValidDBufferMask) { // Return the DBufferMask to the render target pool. // FDeferredPixelShaderParameters will fall back to setting a white dummy mask texture. // This allows us to ignore the DBufferMask on frames without decals, without having to explicitly clear the texture. SceneContext.DBufferMask = nullptr; } }