Files
UnrealEngineUWP/Engine/Source/Runtime/GeometryCache/Private/GeometryCacheSceneProxy.cpp
Marcus Wassmer 8a49574735 Vertex and Index buffer write locks on PS4 no longer require memcopies.
RHi now provides CreateAndLock functions for Vertex and Index buffers which are more efficient on certain platforms.
Use r.PS4StandardWriteLocks=1 to enable the old default functionality for testing if necessary.
#codereview Gil.Grib,Lee.Clark

[CL 2606146 by Marcus Wassmer in Main branch]
2015-06-30 14:18:55 -04:00

343 lines
10 KiB
C++

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#include "GeometryCacheModulePrivatePCH.h"
#include "GeometryCacheSceneProxy.h"
#include "GeometryCacheComponent.h"
#include "GeometryCacheMeshData.h"
FGeometryCacheSceneProxy::FGeometryCacheSceneProxy(UGeometryCacheComponent* Component) : FPrimitiveSceneProxy(Component)
, MaterialRelevance(Component->GetMaterialRelevance(GetScene().GetFeatureLevel()))
{
// Copy each section
const int32 NumSections = Component->TrackSections.Num();
Sections.AddZeroed(NumSections);
for (int SectionIdx = 0; SectionIdx < NumSections; SectionIdx++)
{
FTrackRenderData& SrcSection = Component->TrackSections[SectionIdx];
if (SrcSection.IndexBuffer.Num() > 0)
{
FGeomCacheTrackProxy* NewSection = new FGeomCacheTrackProxy();
NewSection->WorldMatrix = SrcSection.WorldMatrix;
FGeometryCacheMeshData* MeshData = NewSection->MeshData = SrcSection.MeshData;
// Copy data from vertex buffer
const int32 NumVerts = MeshData->Vertices.Num();
// Allocate verts
NewSection->VertexBuffer.Vertices.Empty(NumVerts);
// Copy verts
NewSection->VertexBuffer.Vertices.Append(MeshData->Vertices);
// Copy index buffer
NewSection->IndexBuffer.Indices = SrcSection.IndexBuffer;
// Init vertex factory
NewSection->VertexFactory.Init(&NewSection->VertexBuffer);
// Enqueue initialization of render resource
BeginInitResource(&NewSection->VertexBuffer);
BeginInitResource(&NewSection->IndexBuffer);
BeginInitResource(&NewSection->VertexFactory);
// Grab materials
for (FGeometryCacheMeshBatchInfo& BatchInfo : MeshData->BatchesInfo)
{
UMaterialInterface* Material = Component->GetMaterial(BatchInfo.MaterialIndex);
if (Material == NULL)
{
Material = UMaterial::GetDefaultMaterial(MD_Surface);
}
NewSection->Materials.Push(Material);
}
// Save ref to new section
Sections[SectionIdx] = NewSection;
}
}
}
FGeometryCacheSceneProxy::~FGeometryCacheSceneProxy()
{
for (FGeomCacheTrackProxy* Section : Sections)
{
if (Section != nullptr)
{
Section->VertexBuffer.ReleaseResource();
Section->IndexBuffer.ReleaseResource();
Section->VertexFactory.ReleaseResource();
delete Section;
}
}
Sections.Empty();
}
void FGeometryCacheSceneProxy::GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const
{
SCOPE_CYCLE_COUNTER(STAT_GeometryCacheSceneProxy_GetMeshElements);
// Set up wireframe material (if needed)
const bool bWireframe = AllowDebugViewmodes() && ViewFamily.EngineShowFlags.Wireframe;
FColoredMaterialRenderProxy* WireframeMaterialInstance = NULL;
if (bWireframe)
{
WireframeMaterialInstance = new FColoredMaterialRenderProxy(
GEngine->WireframeMaterial ? GEngine->WireframeMaterial->GetRenderProxy(IsSelected()) : NULL,
FLinearColor(0, 0.5f, 1.f)
);
Collector.RegisterOneFrameMaterialProxy(WireframeMaterialInstance);
}
// Iterate over sections
for (const FGeomCacheTrackProxy* TrackProxy : Sections )
{
// QQQ
if (TrackProxy != nullptr)
{
INC_DWORD_STAT_BY(STAT_GeometryCacheSceneProxy_MeshBatchCount, TrackProxy->MeshData->BatchesInfo.Num());
int32 BatchIndex = 0;
for (FGeometryCacheMeshBatchInfo& BatchInfo : TrackProxy->MeshData->BatchesInfo)
{
FMaterialRenderProxy* MaterialProxy = bWireframe ? WireframeMaterialInstance : TrackProxy->Materials[BatchIndex]->GetRenderProxy(IsSelected());
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
if (VisibilityMap & (1 << ViewIndex))
{
const FSceneView* View = Views[ViewIndex];
// Draw the mesh.
FMeshBatch& Mesh = Collector.AllocateMesh();
FMeshBatchElement& BatchElement = Mesh.Elements[0];
BatchElement.IndexBuffer = &TrackProxy->IndexBuffer;
Mesh.bWireframe = bWireframe;
Mesh.VertexFactory = &TrackProxy->VertexFactory;
Mesh.MaterialRenderProxy = MaterialProxy;
BatchElement.PrimitiveUniformBuffer = CreatePrimitiveUniformBufferImmediate(TrackProxy->WorldMatrix * GetLocalToWorld(), GetBounds(), GetLocalBounds(), true, UseEditorDepthTest());
BatchElement.FirstIndex = BatchInfo.StartIndex;
BatchElement.NumPrimitives = BatchInfo.NumTriangles;
BatchElement.MinVertexIndex = 0;
BatchElement.MaxVertexIndex = TrackProxy->VertexBuffer.Vertices.Num() - 1;
Mesh.ReverseCulling = IsLocalToWorldDeterminantNegative();
Mesh.Type = PT_TriangleList;
Mesh.DepthPriorityGroup = SDPG_World;
Mesh.bCanApplyViewModeOverrides = false;
Collector.AddMesh(ViewIndex, Mesh);
INC_DWORD_STAT_BY(STAT_GeometryCacheSceneProxy_TriangleCount, BatchElement.NumPrimitives);
}
}
++BatchIndex;
}
}
}
// Draw bounds
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
if (VisibilityMap & (1 << ViewIndex))
{
// Render bounds
RenderBounds(Collector.GetPDI(ViewIndex), ViewFamily.EngineShowFlags, GetBounds(), IsSelected());
}
}
#endif
}
FPrimitiveViewRelevance FGeometryCacheSceneProxy::GetViewRelevance(const FSceneView* View)
{
FPrimitiveViewRelevance Result;
Result.bDrawRelevance = IsShown(View);
Result.bShadowRelevance = IsShadowCast(View);
Result.bDynamicRelevance = true;
MaterialRelevance.SetPrimitiveViewRelevance(Result);
return Result;
}
bool FGeometryCacheSceneProxy::CanBeOccluded() const
{
return !MaterialRelevance.bDisableDepthTest;
}
uint32 FGeometryCacheSceneProxy::GetMemoryFootprint(void) const
{
return(sizeof(*this) + GetAllocatedSize());
}
uint32 FGeometryCacheSceneProxy::GetAllocatedSize(void) const
{
return(FPrimitiveSceneProxy::GetAllocatedSize());
}
void FGeometryCacheSceneProxy::UpdateSectionWorldMatrix(const int32 SectionIndex, const FMatrix& WorldMatrix)
{
check(SectionIndex < Sections.Num() && "Section Index out of range");
Sections[SectionIndex]->WorldMatrix = WorldMatrix;
}
void FGeometryCacheSceneProxy::UpdateSectionVertexBuffer(const int32 SectionIndex, FGeometryCacheMeshData* MeshData)
{
check(SectionIndex < Sections.Num() && "Section Index out of range");
check(IsInRenderingThread());
Sections[SectionIndex]->MeshData = MeshData;
const bool bRecreate = Sections[SectionIndex]->VertexBuffer.Vertices.Num() != Sections[SectionIndex]->MeshData->Vertices.Num();
Sections[SectionIndex]->VertexBuffer.Vertices.Empty(Sections[SectionIndex]->MeshData->Vertices.Num());
Sections[SectionIndex]->VertexBuffer.Vertices.Append(Sections[SectionIndex]->MeshData->Vertices);
if (bRecreate)
{
Sections[SectionIndex]->VertexBuffer.InitRHI();
}
else
{
Sections[SectionIndex]->VertexBuffer.UpdateRHI();
}
}
void FGeometryCacheSceneProxy::UpdateSectionIndexBuffer(const int32 SectionIndex, const TArray<int32>& Indices)
{
check(SectionIndex < Sections.Num() && "Section Index out of range");
check(IsInRenderingThread());
const bool bRecreate = Sections[SectionIndex]->IndexBuffer.Indices.Num() != Indices.Num();
Sections[SectionIndex]->IndexBuffer.Indices.Empty(Indices.Num());
Sections[SectionIndex]->IndexBuffer.Indices.Append(Indices);
if (bRecreate)
{
Sections[SectionIndex]->IndexBuffer.InitRHI();
}
else
{
Sections[SectionIndex]->IndexBuffer.UpdateRHI();
}
}
void FGeometryCacheSceneProxy::ClearSections()
{
Sections.Empty();
}
FGeomCacheVertexFactory::FGeomCacheVertexFactory()
{
}
void FGeomCacheVertexFactory::Init_RenderThread(const FGeomCacheVertexBuffer* VertexBuffer)
{
check(IsInRenderingThread());
// Initialize the vertex factory's stream components.
DataType NewData;
NewData.PositionComponent = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, Position, VET_Float3);
NewData.TextureCoordinates.Add(
FVertexStreamComponent(VertexBuffer, STRUCT_OFFSET(FDynamicMeshVertex, TextureCoordinate), sizeof(FDynamicMeshVertex), VET_Float2)
);
NewData.TangentBasisComponents[0] = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, TangentX, VET_PackedNormal);
NewData.TangentBasisComponents[1] = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, TangentZ, VET_PackedNormal);
NewData.ColorComponent = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, Color, VET_Color);
SetData(NewData);
}
void FGeomCacheVertexFactory::Init(const FGeomCacheVertexBuffer* VertexBuffer)
{
if (IsInRenderingThread())
{
Init_RenderThread(VertexBuffer);
}
else
{
ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER(
InitGeomCacheVertexFactory,
FGeomCacheVertexFactory*, VertexFactory, this,
const FGeomCacheVertexBuffer*, VertexBuffer, VertexBuffer,
{
VertexFactory->Init_RenderThread(VertexBuffer);
});
}
}
void FGeomCacheIndexBuffer::InitRHI()
{
FRHIResourceCreateInfo CreateInfo;
void* Buffer = nullptr;
IndexBufferRHI = RHICreateAndLockIndexBuffer(sizeof(int32), Indices.Num() * sizeof(int32), BUF_Static, CreateInfo);
// Write the indices to the index buffer.
FMemory::Memcpy(Buffer, Indices.GetData(), Indices.Num() * sizeof(int32));
RHIUnlockIndexBuffer(IndexBufferRHI);
}
void FGeomCacheIndexBuffer::UpdateRHI()
{
// Copy the index data into the index buffer.
void* Buffer = RHILockIndexBuffer(IndexBufferRHI, 0, Indices.Num() * sizeof(int32), RLM_WriteOnly);
FMemory::Memcpy(Buffer, Indices.GetData(), Indices.Num() * sizeof(int32));
RHIUnlockIndexBuffer(IndexBufferRHI);
}
void FGeomCacheVertexBuffer::InitRHI()
{
const uint32 SizeInBytes = Vertices.Num() * sizeof(FDynamicMeshVertex);
FGeomCacheVertexResourceArray ResourceArray(Vertices.GetData(), SizeInBytes);
FRHIResourceCreateInfo CreateInfo(&ResourceArray);
VertexBufferRHI = RHICreateVertexBuffer(SizeInBytes, BUF_Static, CreateInfo);
}
void FGeomCacheVertexBuffer::UpdateRHI()
{
// 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);
}
FGeomCacheVertexResourceArray::FGeomCacheVertexResourceArray(void* InData, uint32 InSize) : Data(InData)
, Size(InSize)
{
}
const void* FGeomCacheVertexResourceArray::GetResourceData() const
{
return Data;
}
uint32 FGeomCacheVertexResourceArray::GetResourceDataSize() const
{
return Size;
}
void FGeomCacheVertexResourceArray::Discard()
{
}
bool FGeomCacheVertexResourceArray::IsStatic() const
{
return false;
}
bool FGeomCacheVertexResourceArray::GetAllowCPUAccess() const
{
return false;
}
void FGeomCacheVertexResourceArray::SetAllowCPUAccess(bool bInNeedsCPUAccess)
{
}