virtual void InitRHI() override { #if ENGINE_MAJOR_VERSION >= 4 && ENGINE_MINOR_VERSION >= 3 FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(BOSize * sizeof(FDynamicMeshVertex), BUF_AnyDynamic, CreateInfo); #else VertexBufferRHI = RHICreateVertexBuffer(BOSize * sizeof(FDynamicMeshVertex), NULL, BUF_AnyDynamic); #endif }
virtual void InitRHI() override { #if ENGINE_MAJOR_VERSION >= 4 && ENGINE_MINOR_VERSION >= 3 FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(Vertices.Num() * sizeof(FDynamicMeshVertex), BUF_Static, CreateInfo); #else VertexBufferRHI = RHICreateVertexBuffer(Vertices.Num() * sizeof(FDynamicMeshVertex), NULL, BUF_Static); #endif // Copy the vertex data into the vertex buffer. void* VertexBufferData = RHILockVertexBuffer(VertexBufferRHI, 0, Vertices.Num() * sizeof(FDynamicMeshVertex), RLM_WriteOnly); FMemory::Memcpy(VertexBufferData, Vertices.GetData(), Vertices.Num() * sizeof(FDynamicMeshVertex)); RHIUnlockVertexBuffer(VertexBufferRHI); }
/** Initialize the RHI for this rendering resource */ void InitRHI() override { TResourceArray<FFilterVertex, VERTEXBUFFER_ALIGNMENT> Vertices; Vertices.SetNumUninitialized(6); Vertices[0].Position = FVector4(1, 1, 0, 1); Vertices[0].UV = FVector2D(1, 1); Vertices[1].Position = FVector4(0, 1, 0, 1); Vertices[1].UV = FVector2D(0, 1); Vertices[2].Position = FVector4(1, 0, 0, 1); Vertices[2].UV = FVector2D(1, 0); Vertices[3].Position = FVector4(0, 0, 0, 1); Vertices[3].UV = FVector2D(0, 0); //The final two vertices are used for the triangle optimization (a single triangle spans the entire viewport ) Vertices[4].Position = FVector4(-1, 1, 0, 1); Vertices[4].UV = FVector2D(-1, 1); Vertices[5].Position = FVector4(1, -1, 0, 1); Vertices[5].UV = FVector2D(1, -1); // Create vertex buffer. Fill buffer with initial data upon creation FRHIResourceCreateInfo CreateInfo(&Vertices); VertexBufferRHI = RHICreateVertexBuffer(Vertices.GetResourceDataSize(), BUF_Static, CreateInfo); }
/** * Initialize the RHI for this rendering resource */ void InitRHI() override { const int32 NumVerts = 8; TResourceArray<FVector4, VERTEXBUFFER_ALIGNMENT> Verts; Verts.SetNumUninitialized(NumVerts); for (uint32 Z = 0; Z < 2; Z++) { for (uint32 Y = 0; Y < 2; Y++) { for (uint32 X = 0; X < 2; X++) { const FVector4 Vertex = FVector4( (X ? -1 : 1), (Y ? -1 : 1), (Z ? -1 : 1), 1.0f ); Verts[GetCubeVertexIndex(X, Y, Z)] = Vertex; } } } uint32 Size = Verts.GetResourceDataSize(); // Create vertex buffer. Fill buffer with initial data upon creation FRHIResourceCreateInfo CreateInfo(&Verts); VertexBufferRHI = RHICreateVertexBuffer(Size, BUF_Static, CreateInfo); }
void FFinalSkinVertexBuffer::InitVertexData(FStaticLODModel& LodModel) { // Create the buffer rendering resource uint32 Size = LodModel.NumVertices * sizeof(FFinalSkinVertex); FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(Size,BUF_Dynamic, CreateInfo); // Lock the buffer. void* Buffer = RHILockVertexBuffer(VertexBufferRHI,0,Size,RLM_WriteOnly); // Initialize the vertex data // All chunks are combined into one (rigid first, soft next) check(LodModel.VertexBufferGPUSkin.GetNumVertices() == LodModel.NumVertices); FFinalSkinVertex* DestVertex = (FFinalSkinVertex*)Buffer; for( uint32 VertexIdx=0; VertexIdx < LodModel.NumVertices; VertexIdx++ ) { const TGPUSkinVertexBase<bExtraBoneInfluencesT>* SrcVertex = LodModel.VertexBufferGPUSkin.GetVertexPtr<bExtraBoneInfluencesT>(VertexIdx); DestVertex->Position = LodModel.VertexBufferGPUSkin.GetVertexPositionFast<bExtraBoneInfluencesT>(VertexIdx); DestVertex->TangentX = SrcVertex->TangentX; // w component of TangentZ should already have sign of the tangent basis determinant DestVertex->TangentZ = SrcVertex->TangentZ; FVector2D UVs = LodModel.VertexBufferGPUSkin.GetVertexUVFast<bExtraBoneInfluencesT>(VertexIdx,0); DestVertex->U = UVs.X; DestVertex->V = UVs.Y; DestVertex++; } // Unlock the buffer. RHIUnlockVertexBuffer(VertexBufferRHI); }
/** * Initialize the dynamic RHI for this rendering resource */ void FMorphVertexBuffer::InitDynamicRHI() { // LOD of the skel mesh is used to find number of vertices in buffer FStaticLODModel& LodModel = SkelMeshResource->LODModels[LODIdx]; // Create the buffer rendering resource uint32 Size = LodModel.NumVertices * sizeof(FMorphGPUSkinVertex); FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(Size,BUF_Dynamic,CreateInfo); // Lock the buffer. FMorphGPUSkinVertex* Buffer = (FMorphGPUSkinVertex*) RHILockVertexBuffer(VertexBufferRHI,0,Size,RLM_WriteOnly); // zero all deltas (NOTE: DeltaTangentZ is FPackedNormal, so we can't just FMemory::Memzero) for (uint32 VertIndex=0; VertIndex < LodModel.NumVertices; ++VertIndex) { Buffer[VertIndex].DeltaPosition = FVector::ZeroVector; Buffer[VertIndex].DeltaTangentZ = FPackedNormal::ZeroNormal; } // Unlock the buffer. RHIUnlockVertexBuffer(VertexBufferRHI); // hasn't been updated yet bHasBeenUpdated = false; }
// // VertexBuffer // void FSsPartsVertexBuffer::InitRHI() { if(0 < NumVerts) { FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(NumVerts * sizeof(FSsPartVertex), BUF_Dynamic, CreateInfo); } }
virtual void InitRHI() override { const uint32 SizeInBytes = Vertices.Num() * sizeof(FDynamicMeshVertex); FProcMeshVertexResourceArray ResourceArray(Vertices.GetData(), SizeInBytes); FRHIResourceCreateInfo CreateInfo(&ResourceArray); VertexBufferRHI = RHICreateVertexBuffer(SizeInBytes, BUF_Static, CreateInfo); }
virtual void InitRHI() override { FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(Vertices.Num() * sizeof(FDynamicMeshVertex), BUF_Static, CreateInfo); // Copy the vertex data into the vertex buffer. void* VertexBufferData = RHILockVertexBuffer(VertexBufferRHI, 0, Vertices.Num() * sizeof(FDynamicMeshVertex), RLM_WriteOnly); FMemory::Memcpy(VertexBufferData, Vertices.GetData(), Vertices.Num() * sizeof(FDynamicMeshVertex)); RHIUnlockVertexBuffer(VertexBufferRHI); }
static FVertexBufferRHIRef AllocVertexBuffer(uint32 Stride, uint32 NumElements) { FVertexBufferRHIRef VertexBufferRHI; uint32 SizeInBytes = NumElements * Stride; FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(SizeInBytes, BUF_Volatile | BUF_ShaderResource, CreateInfo); return VertexBufferRHI; }
virtual void InitRHI() override { FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(sizeof(FVector4) * 2, BUF_Static, CreateInfo); FVector4* DummyContents = (FVector4*)RHILockVertexBuffer(VertexBufferRHI,0,sizeof(FVector4)*2,RLM_WriteOnly); DummyContents[0] = FVector4(0.0f, 0.0f, 0.0f, 0.0f); DummyContents[1] = FVector4(1.0f, 1.0f, 1.0f, 1.0f); RHIUnlockVertexBuffer(VertexBufferRHI); }
/*----------------------------------------------------------------------------- FBoneBufferPoolPolicy -----------------------------------------------------------------------------*/ FBoneBufferTypeRef FBoneBufferPoolPolicy::CreateResource(CreationArguments Args) { uint32 BufferSize = GetPoolBucketSize(GetPoolBucketIndex(Args)); FBoneBuffer Buffer; FRHIResourceCreateInfo CreateInfo; Buffer.VertexBufferRHI = RHICreateVertexBuffer( BufferSize, (BUF_Dynamic | BUF_ShaderResource), CreateInfo ); Buffer.VertexBufferSRV = RHICreateShaderResourceView( Buffer.VertexBufferRHI, sizeof(FVector4), PF_A32B32G32R32F ); return Buffer; }
virtual void InitRHI() { VertexBufferRHI = RHICreateVertexBuffer(Vertices.Num() * sizeof(FDynamicMeshVertex), NULL, BUF_Static); // Copy the vertex data into the vertex buffer. void* VertexBufferData = RHILockVertexBuffer(VertexBufferRHI, 0, Vertices.Num() * sizeof(FDynamicMeshVertex), RLM_WriteOnly); FMemory::Memcpy(VertexBufferData, Vertices.GetTypedData(), Vertices.Num() * sizeof(FDynamicMeshVertex)); RHIUnlockVertexBuffer(VertexBufferRHI); }
void FPaperSpriteVertexBuffer::InitRHI() { const uint32 SizeInBytes = Vertices.Num() * sizeof(FPaperSpriteVertex); FDummyResourceArrayWrapper Wrapper(Vertices.GetData(), SizeInBytes); FRHIResourceCreateInfo CreateInfo(&Wrapper); VertexBufferRHI = RHICreateVertexBuffer(SizeInBytes, BUF_Static, CreateInfo); Vertices.Empty(); }
void FPositionVertexBuffer::InitRHI() { check(VertexData); FResourceArrayInterface* ResourceArray = VertexData->GetResourceArray(); if(ResourceArray->GetResourceDataSize()) { // Create the vertex buffer. VertexBufferRHI = RHICreateVertexBuffer(ResourceArray->GetResourceDataSize(),ResourceArray,BUF_Static); } }
void FColorVertexBuffer::InitRHI() { if( VertexData != NULL ) { FResourceArrayInterface* ResourceArray = VertexData->GetResourceArray(); if(ResourceArray->GetResourceDataSize()) { // Create the vertex buffer. FRHIResourceCreateInfo CreateInfo(ResourceArray); VertexBufferRHI = RHICreateVertexBuffer(ResourceArray->GetResourceDataSize(),BUF_Static,CreateInfo); } } }
void FUniformMeshBuffers::Initialize() { if (MaxElements > 0) { const int32 VertexStride = ComputeUniformVertexStride(); FRHIResourceCreateInfo CreateInfo; TriangleData = RHICreateVertexBuffer(MaxElements * VertexStride * GPixelFormats[PF_R32_FLOAT].BlockBytes, BUF_ShaderResource | BUF_StreamOutput, CreateInfo); TriangleDataSRV = RHICreateShaderResourceView(TriangleData, GPixelFormats[PF_R32_FLOAT].BlockBytes, PF_R32_FLOAT); TriangleAreas.Initialize(sizeof(float), MaxElements, PF_R32_FLOAT); TriangleCDFs.Initialize(sizeof(float), MaxElements, PF_R32_FLOAT); } }
/** * Creates a scratch vertex buffer available for dynamic draw calls. */ void FParticleScratchVertexBuffer::InitRHI() { // Create a scratch vertex buffer for injecting particles and rendering tiles. uint32 Flags = BUF_Volatile; if (GRHIFeatureLevel >= ERHIFeatureLevel::SM4) { Flags |= BUF_ShaderResource; } VertexBufferRHI = RHICreateVertexBuffer(GParticleScratchVertexBufferSize, NULL, Flags); if (GRHIFeatureLevel >= ERHIFeatureLevel::SM4) { VertexBufferSRV_G32R32F = RHICreateShaderResourceView( VertexBufferRHI, /*Stride=*/ sizeof(FVector2D), PF_G32R32F ); } }
void FStreetMapVertexBuffer::InitRHI() { if( Vertices.Num() > 0 ) { // Allocate our vertex buffer FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer( Vertices.Num() * sizeof( Vertices[0] ), BUF_Static, CreateInfo ); // Load the vertex buffer with data void* VertexBufferData = RHILockVertexBuffer( VertexBufferRHI, 0, Vertices.Num() * sizeof( Vertices[0] ), RLM_WriteOnly ); FMemory::Memcpy( VertexBufferData, Vertices.GetData(), Vertices.Num() * sizeof( FStreetMapVertex ) ); RHIUnlockVertexBuffer( VertexBufferRHI ); } }
/** * Creates a vertex buffer holding texture coordinates for the four corners of a sprite. */ void FParticleTexCoordVertexBuffer::InitRHI() { const uint32 Size = sizeof(FVector2D) * 4 * MAX_PARTICLES_PER_INSTANCE; VertexBufferRHI = RHICreateVertexBuffer( Size, NULL, BUF_Static ); FVector2D* Vertices = (FVector2D*)RHILockVertexBuffer( VertexBufferRHI, 0, Size, RLM_WriteOnly ); for (uint32 SpriteIndex = 0; SpriteIndex < MAX_PARTICLES_PER_INSTANCE; ++SpriteIndex) { Vertices[SpriteIndex*4 + 0] = FVector2D(0.0f, 0.0f); Vertices[SpriteIndex*4 + 1] = FVector2D(0.0f, 1.0f); Vertices[SpriteIndex*4 + 2] = FVector2D(1.0f, 1.0f); Vertices[SpriteIndex*4 + 3] = FVector2D(1.0f, 0.0f); } RHIUnlockVertexBuffer( VertexBufferRHI ); }
/** * Creates a scratch vertex buffer available for dynamic draw calls. */ void FParticleScratchVertexBuffer::InitRHI() { // Create a scratch vertex buffer for injecting particles and rendering tiles. uint32 Flags = BUF_Volatile; if (GSupportsResourceView) { Flags |= BUF_ShaderResource; } FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(GParticleScratchVertexBufferSize, Flags, CreateInfo); if (GSupportsResourceView) { VertexBufferSRV_G32R32F = RHICreateShaderResourceView( VertexBufferRHI, /*Stride=*/ sizeof(FVector2D), PF_G32R32F ); } }
virtual void InitRHI() { FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(12 * sizeof(FPackedNormal), BUF_Dynamic, CreateInfo); // Copy the vertex data into the vertex buffer. FPackedNormal* TangentBufferData = (FPackedNormal*)RHILockVertexBuffer(VertexBufferRHI, 0, 12 * sizeof(FPackedNormal), RLM_WriteOnly); for(int32 FaceIndex = 0;FaceIndex < 6;++FaceIndex) { const FVector UnprojectedTangentX = FVector(+1,-1,0).GetSafeNormal(); const FVector UnprojectedTangentY(-1,-1,-1); const FVector FaceNormal = FaceNormals[FaceIndex].ToFloat(); const FVector ProjectedFaceTangentX = (UnprojectedTangentX - FaceNormal * (UnprojectedTangentX | FaceNormal)).GetSafeNormal(); *TangentBufferData++ = ProjectedFaceTangentX; *TangentBufferData++ = FVector4(FaceNormal, FMath::Sign(UnprojectedTangentY | (FaceNormal ^ ProjectedFaceTangentX))); } RHIUnlockVertexBuffer(VertexBufferRHI); }
/** * Initialize the RHI for this rendering resource */ virtual void InitRHI() override { // used with a tristrip, so only 4 vertices are needed uint32 Size = 4 * sizeof(FMaterialTileVertex); // create vertex buffer FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(Size,BUF_Static,CreateInfo); // lock it void* Buffer = RHILockVertexBuffer(VertexBufferRHI,0,Size,RLM_WriteOnly); // first vertex element FMaterialTileVertex* DestVertex = (FMaterialTileVertex*)Buffer; // fill out the verts DestVertex[0].Initialize(1, -1, 1, 1); DestVertex[1].Initialize(1, 1, 1, 0); DestVertex[2].Initialize(-1, -1, 0, 1); DestVertex[3].Initialize(-1, 1, 0, 0); // Unlock the buffer. RHIUnlockVertexBuffer(VertexBufferRHI); }
virtual void InitRHI() override { FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(NumVerts * sizeof(FDynamicMeshVertex), BUF_Dynamic, CreateInfo); }
virtual void InitRHI() { VertexBufferRHI = RHICreateVertexBuffer(NumVerts * sizeof(FDynamicMeshVertex), NULL, BUF_Dynamic); }
virtual void InitRHI() override { FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(Vertices.Num() * sizeof(FDynamicMeshVertex), BUF_Static, CreateInfo); UpdateRenderData(); }
void RendererGPUBenchmark(FRHICommandListImmediate& RHICmdList, FSynthBenchmarkResults& InOut, const FSceneView& View, float WorkScale, bool bDebugOut) { check(IsInRenderingThread()); FRenderQueryPool TimerQueryPool(RQT_AbsoluteTime); bool bValidGPUTimer = (FGPUTiming::GetTimingFrequency() / (1000 * 1000)) != 0; if(!bValidGPUTimer) { UE_LOG(LogSynthBenchmark, Warning, TEXT("RendererGPUBenchmark failed, look for \"GPU Timing Frequency\" in the log")); return; } TResourceArray<FBenchmarkVertex> Vertices; Vertices.Reserve(GBenchmarkVertices); for (uint32 Index = 0; Index < GBenchmarkVertices; ++Index) { Vertices.Emplace(Index); } FRHIResourceCreateInfo CreateInfo(&Vertices); FVertexBufferRHIRef VertexBuffer = RHICreateVertexBuffer(GBenchmarkVertices * sizeof(FBenchmarkVertex), BUF_Static, CreateInfo); // two RT to ping pong so we force the GPU to flush it's pipeline TRefCountPtr<IPooledRenderTarget> RTItems[3]; { FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(FIntPoint(GBenchmarkResolution, GBenchmarkResolution), PF_B8G8R8A8, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable | TexCreate_ShaderResource, false)); Desc.AutoWritable = false; GRenderTargetPool.FindFreeElement(RHICmdList, Desc, RTItems[0], TEXT("Benchmark0")); GRenderTargetPool.FindFreeElement(RHICmdList, Desc, RTItems[1], TEXT("Benchmark1")); Desc.Extent = FIntPoint(1, 1); Desc.Flags = TexCreate_CPUReadback; // needs TexCreate_ResolveTargetable? Desc.TargetableFlags = TexCreate_None; GRenderTargetPool.FindFreeElement(RHICmdList, Desc, RTItems[2], TEXT("BenchmarkReadback")); } // set the state RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI()); RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false,CF_Always>::GetRHI()); { // larger number means more accuracy but slower, some slower GPUs might timeout with a number to large const uint32 IterationCount = 70; const uint32 MethodCount = ARRAY_COUNT(InOut.GPUStats); enum class EMethodType { Vertex, Pixel }; struct FBenchmarkMethod { const TCHAR* Desc; float IndexNormalizedTime; const TCHAR* ValueType; float Weight; EMethodType Type; }; const FBenchmarkMethod Methods[] = { // e.g. on NV670: Method3 (mostly fill rate )-> 26GP/s (seems realistic) // reference: http://en.wikipedia.org/wiki/Comparison_of_Nvidia_graphics_processing_units theoretical: 29.3G/s { TEXT("ALUHeavyNoise"), 1.0f / 4.601f, TEXT("s/GigaPix"), 1.0f, EMethodType::Pixel }, { TEXT("TexHeavy"), 1.0f / 7.447f, TEXT("s/GigaPix"), 0.1f, EMethodType::Pixel }, { TEXT("DepTexHeavy"), 1.0f / 3.847f, TEXT("s/GigaPix"), 0.1f, EMethodType::Pixel }, { TEXT("FillOnly"), 1.0f / 25.463f, TEXT("s/GigaPix"), 3.0f, EMethodType::Pixel }, { TEXT("Bandwidth"), 1.0f / 1.072f, TEXT("s/GigaPix"), 1.0f, EMethodType::Pixel }, { TEXT("VertThroughPut1"), 1.0f / 1.537f, TEXT("s/GigaVert"), 0.0f, EMethodType::Vertex }, // TODO: Set weights { TEXT("VertThroughPut2"), 1.0f / 1.767f, TEXT("s/GigaVert"), 0.0f, EMethodType::Vertex }, // TODO: Set weights }; static_assert(ARRAY_COUNT(Methods) == ARRAY_COUNT(InOut.GPUStats), "Benchmark methods descriptor array lengths should match."); // Initialize the GPU benchmark stats for (int32 Index = 0; Index < ARRAY_COUNT(Methods); ++Index) { auto& Method = Methods[Index]; InOut.GPUStats[Index] = FSynthBenchmarkStat(Method.Desc, Method.IndexNormalizedTime, Method.ValueType, Method.Weight); } // 0 / 1 uint32 DestRTIndex = 0; const uint32 TimerSampleCount = IterationCount * MethodCount + 1; static FRenderQueryRHIRef TimerQueries[TimerSampleCount]; static float LocalWorkScale[IterationCount]; for(uint32 i = 0; i < TimerSampleCount; ++i) { TimerQueries[i] = TimerQueryPool.AllocateQuery(); } const bool bSupportsTimerQueries = (TimerQueries[0] != NULL); if(!bSupportsTimerQueries) { UE_LOG(LogSynthBenchmark, Warning, TEXT("GPU driver does not support timer queries.")); // Temporary workaround for GL_TIMESTAMP being unavailable and GL_TIME_ELAPSED workaround breaking drivers #if PLATFORM_MAC GLint RendererID = 0; float PerfScale = 1.0f; [[NSOpenGLContext currentContext] getValues:&RendererID forParameter:NSOpenGLCPCurrentRendererID]; { switch((RendererID & kCGLRendererIDMatchingMask)) { case kCGLRendererATIRadeonX4000ID: // AMD 7xx0 & Dx00 series - should be pretty beefy PerfScale = 1.2f; break; case kCGLRendererATIRadeonX3000ID: // AMD 5xx0, 6xx0 series - mostly OK case kCGLRendererGeForceID: // Nvidia 6x0 & 7x0 series - mostly OK PerfScale = 2.0f; break; case kCGLRendererIntelHD5000ID: // Intel HD 5000, Iris, Iris Pro - not dreadful PerfScale = 4.2f; break; case kCGLRendererIntelHD4000ID: // Intel HD 4000 - quite slow PerfScale = 7.5f; break; case kCGLRendererATIRadeonX2000ID: // ATi 4xx0, 3xx0, 2xx0 - almost all very slow and drivers are now very buggy case kCGLRendererGeForce8xxxID: // Nvidia 3x0, 2x0, 1x0, 9xx0, 8xx0 - almost all very slow case kCGLRendererIntelHDID: // Intel HD 3000 - very, very slow and very buggy driver default: PerfScale = 10.0f; break; } } for (int32 Index = 0; Index < MethodCount; ++Index) { FSynthBenchmarkStat& Stat = InOut.GPUStats[Index]; Stat.SetMeasuredTime(FTimeSample(PerfScale, PerfScale * Methods[Index].IndexNormalizedTime)); } #endif return; } // TimingValues are in Seconds FTimingSeries TimingSeries[MethodCount]; // in 1/1000000 Seconds uint64 TotalTimes[MethodCount]; for(uint32 MethodIterator = 0; MethodIterator < MethodCount; ++MethodIterator) { TotalTimes[MethodIterator] = 0; TimingSeries[MethodIterator].Init(IterationCount); } RHICmdList.EndRenderQuery(TimerQueries[0]); // multiple iterations to see how trust able the values are for(uint32 Iteration = 0; Iteration < IterationCount; ++Iteration) { for(uint32 MethodIterator = 0; MethodIterator < MethodCount; ++MethodIterator) { // alternate between forward and backward (should give the same number) // uint32 MethodId = (Iteration % 2) ? MethodIterator : (MethodCount - 1 - MethodIterator); uint32 MethodId = MethodIterator; uint32 QueryIndex = 1 + Iteration * MethodCount + MethodId; // 0 / 1 const uint32 SrcRTIndex = 1 - DestRTIndex; GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, RTItems[DestRTIndex]); SetRenderTarget(RHICmdList, RTItems[DestRTIndex]->GetRenderTargetItem().TargetableTexture, FTextureRHIRef(), true); // decide how much work we do in this pass LocalWorkScale[Iteration] = (Iteration / 10.f + 1.f) * WorkScale; RunBenchmarkShader(RHICmdList, VertexBuffer, View, MethodId, RTItems[SrcRTIndex], LocalWorkScale[Iteration]); RHICmdList.CopyToResolveTarget(RTItems[DestRTIndex]->GetRenderTargetItem().TargetableTexture, RTItems[DestRTIndex]->GetRenderTargetItem().ShaderResourceTexture, false, FResolveParams()); /*if(bGPUCPUSync) { // more consistent timing but strangely much faster to the level that is unrealistic FResolveParams Param; Param.Rect = FResolveRect(0, 0, 1, 1); RHICmdList.CopyToResolveTarget( RTItems[DestRTIndex]->GetRenderTargetItem().TargetableTexture, RTItems[2]->GetRenderTargetItem().ShaderResourceTexture, false, Param); void* Data = 0; int Width = 0; int Height = 0; RHIMapStagingSurface(RTItems[2]->GetRenderTargetItem().ShaderResourceTexture, Data, Width, Height); RHIUnmapStagingSurface(RTItems[2]->GetRenderTargetItem().ShaderResourceTexture); }*/ RHICmdList.EndRenderQuery(TimerQueries[QueryIndex]); // ping pong DestRTIndex = 1 - DestRTIndex; } } { uint64 OldAbsTime = 0; // flushes the RHI thread to make sure all RHICmdList.EndRenderQuery() commands got executed. RHICmdList.ImmediateFlush(EImmediateFlushType::FlushRHIThread); RHICmdList.GetRenderQueryResult(TimerQueries[0], OldAbsTime, true); TimerQueryPool.ReleaseQuery(TimerQueries[0]); for(uint32 Iteration = 0; Iteration < IterationCount; ++Iteration) { uint32 Results[MethodCount]; for(uint32 MethodId = 0; MethodId < MethodCount; ++MethodId) { uint32 QueryIndex = 1 + Iteration * MethodCount + MethodId; uint64 AbsTime; RHICmdList.GetRenderQueryResult(TimerQueries[QueryIndex], AbsTime, true); TimerQueryPool.ReleaseQuery(TimerQueries[QueryIndex]); uint64 RelTime = FMath::Max(AbsTime - OldAbsTime, 1ull); TotalTimes[MethodId] += RelTime; Results[MethodId] = RelTime; OldAbsTime = AbsTime; } for(uint32 MethodId = 0; MethodId < MethodCount; ++MethodId) { float TimeInSec = Results[MethodId] / 1000000.0f; if (Methods[MethodId].Type == EMethodType::Vertex) { // to normalize from seconds to seconds per GVert float SamplesInGVert = LocalWorkScale[Iteration] * GBenchmarkVertices / 1000000000.0f; TimingSeries[MethodId].SetEntry(Iteration, TimeInSec / SamplesInGVert); } else { check(Methods[MethodId].Type == EMethodType::Pixel); // to normalize from seconds to seconds per GPixel float SamplesInGPix = LocalWorkScale[Iteration] * GBenchmarkResolution * GBenchmarkResolution / 1000000000.0f; // TimingValue in Seconds per GPixel TimingSeries[MethodId].SetEntry(Iteration, TimeInSec / SamplesInGPix); } } } if(bSupportsTimerQueries) { for(uint32 MethodId = 0; MethodId < MethodCount; ++MethodId) { float Confidence = 0.0f; // in seconds per GPixel float NormalizedTime = TimingSeries[MethodId].ComputeValue(Confidence); if(Confidence > 0) { FTimeSample TimeSample(TotalTimes[MethodId] / 1000000.0f, NormalizedTime); InOut.GPUStats[MethodId].SetMeasuredTime(TimeSample, Confidence); } } } } }
// VertexBuffer void FSsPlaneVertexBuffer::InitRHI() { FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(NumVerts * sizeof(FDynamicMeshVertex), BUF_Dynamic, CreateInfo); }