Fix Mesh data downloading to support not yet streamed vertex/index data gather

#932
This commit is contained in:
Wojtek Figat
2023-02-16 13:47:43 +01:00
parent 067b8144ad
commit 123b7f5433
6 changed files with 158 additions and 202 deletions

View File

@@ -527,9 +527,8 @@ namespace FlaxEngine
/// <returns>The gathered data.</returns>
public Vertex0[] DownloadVertexBuffer0(bool forceGpu = false)
{
var vertices = VertexCount;
var result = new Vertex0[vertices];
if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB0))
var result = (Vertex0[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(Vertex0), (int)InternalBufferType.VB0);
if (result == null)
throw new Exception("Failed to download mesh data.");
return result;
}
@@ -541,9 +540,8 @@ namespace FlaxEngine
/// <returns>The gathered data.</returns>
public Vertex1[] DownloadVertexBuffer1(bool forceGpu = false)
{
var vertices = VertexCount;
var result = new Vertex1[vertices];
if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB1))
var result = (Vertex1[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(Vertex1), (int)InternalBufferType.VB1);
if (result == null)
throw new Exception("Failed to download mesh data.");
return result;
}
@@ -560,10 +558,8 @@ namespace FlaxEngine
{
if (!HasVertexColors)
return null;
var vertices = VertexCount;
var result = new Vertex2[vertices];
if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB2))
var result = (Vertex2[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(Vertex2), (int)InternalBufferType.VB2);
if (result == null)
throw new Exception("Failed to download mesh data.");
return result;
}
@@ -582,7 +578,7 @@ namespace FlaxEngine
var vb1 = DownloadVertexBuffer1(forceGpu);
var vb2 = DownloadVertexBuffer2(forceGpu);
var vertices = VertexCount;
var vertices = vb0.Length;
var result = new Vertex[vertices];
for (int i = 0; i < vertices; i++)
{
@@ -618,9 +614,8 @@ namespace FlaxEngine
/// <returns>The gathered data.</returns>
public uint[] DownloadIndexBuffer(bool forceGpu = false)
{
var triangles = TriangleCount;
var result = new uint[triangles * 3];
if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB32))
var result = (uint[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(uint), (int)InternalBufferType.IB32);
if (result == null)
throw new Exception("Failed to download mesh data.");
return result;
}
@@ -633,9 +628,8 @@ namespace FlaxEngine
/// <returns>The gathered data.</returns>
public ushort[] DownloadIndexBufferUShort(bool forceGpu = false)
{
var triangles = TriangleCount;
var result = new ushort[triangles * 3];
if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB16))
var result = (ushort[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(ushort), (int)InternalBufferType.IB16);
if (result == null)
throw new Exception("Failed to download mesh data.");
return result;
}

View File

@@ -746,75 +746,11 @@ enum class InternalBufferType
IB32 = 4,
};
void ConvertMeshData(Mesh* mesh, InternalBufferType type, MonoArray* resultObj, void* srcData)
MonoArray* Mesh::DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI)
{
auto vertices = mesh->GetVertexCount();
auto triangles = mesh->GetTriangleCount();
auto indices = triangles * 3;
auto use16BitIndexBuffer = mesh->Use16BitIndexBuffer();
void* managedArrayPtr = mono_array_addr_with_size(resultObj, 0, 0);
switch (type)
{
case InternalBufferType::VB0:
{
Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(VB0ElementType) * vertices);
break;
}
case InternalBufferType::VB1:
{
Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(VB1ElementType) * vertices);
break;
}
case InternalBufferType::VB2:
{
Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(VB2ElementType) * vertices);
break;
}
case InternalBufferType::IB16:
{
if (use16BitIndexBuffer)
{
Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(uint16) * indices);
}
else
{
auto dst = (uint16*)managedArrayPtr;
auto src = (uint32*)srcData;
for (int32 i = 0; i < indices; i++)
{
dst[i] = src[i];
}
}
break;
}
case InternalBufferType::IB32:
{
if (use16BitIndexBuffer)
{
auto dst = (uint32*)managedArrayPtr;
auto src = (uint16*)srcData;
for (int32 i = 0; i < indices; i++)
{
dst[i] = src[i];
}
}
else
{
Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(uint32) * indices);
}
break;
}
}
}
bool Mesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI)
{
Mesh* mesh = this;
InternalBufferType type = (InternalBufferType)typeI;
auto mesh = this;
auto type = (InternalBufferType)typeI;
auto model = mesh->GetModel();
ASSERT(model && resultObj);
ScopeLock lock(model->Locker);
// Virtual assets always fetch from GPU memory
@@ -823,23 +759,7 @@ bool Mesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI)
if (!mesh->IsInitialized() && forceGpu)
{
LOG(Error, "Cannot load mesh data from GPU if it's not loaded.");
return true;
}
if (type == InternalBufferType::IB16 || type == InternalBufferType::IB32)
{
if (mono_array_length(resultObj) != mesh->GetTriangleCount() * 3)
{
LOG(Error, "Invalid buffer size.");
return true;
}
}
else
{
if (mono_array_length(resultObj) != mesh->GetVertexCount())
{
LOG(Error, "Invalid buffer size.");
return true;
}
return nullptr;
}
MeshBufferType bufferType;
@@ -859,35 +779,96 @@ bool Mesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI)
bufferType = MeshBufferType::Index;
break;
default:
return true;
return nullptr;
}
BytesContainer data;
int32 dataCount;
if (forceGpu)
{
// Get data from GPU
// TODO: support reusing the input memory buffer to perform a single copy from staging buffer to the input CPU buffer
auto task = mesh->DownloadDataGPUAsync(bufferType, data);
if (task == nullptr)
return true;
return nullptr;
task->Start();
model->Locker.Unlock();
if (task->Wait())
{
LOG(Error, "Task failed.");
return true;
return nullptr;
}
model->Locker.Lock();
// Extract elements count from result data
switch (bufferType)
{
case MeshBufferType::Index:
dataCount = data.Length() / (Use16BitIndexBuffer() ? sizeof(uint16) : sizeof(uint32));
break;
case MeshBufferType::Vertex0:
dataCount = data.Length() / sizeof(VB0ElementType);
break;
case MeshBufferType::Vertex1:
dataCount = data.Length() / sizeof(VB1ElementType);
break;
case MeshBufferType::Vertex2:
dataCount = data.Length() / sizeof(VB2ElementType);
break;
}
}
else
{
// Get data from CPU
int32 count;
if (DownloadDataCPU(bufferType, data, count))
return true;
if (DownloadDataCPU(bufferType, data, dataCount))
return nullptr;
}
ConvertMeshData(mesh, type, resultObj, data.Get());
return false;
// Convert into managed array
MonoArray* result = mono_array_new(mono_domain_get(), mono_type_get_class(mono_reflection_type_get_type(resultType)), dataCount);
void* managedArrayPtr = mono_array_addr_with_size(result, 0, 0);
const int32 elementSize = data.Length() / dataCount;
switch (type)
{
case InternalBufferType::VB0:
case InternalBufferType::VB1:
case InternalBufferType::VB2:
{
Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length());
break;
}
case InternalBufferType::IB16:
{
if (elementSize == sizeof(uint16))
{
Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length());
}
else
{
auto dst = (uint16*)managedArrayPtr;
auto src = (uint32*)data.Get();
for (int32 i = 0; i < dataCount; i++)
dst[i] = src[i];
}
break;
}
case InternalBufferType::IB32:
{
if (elementSize == sizeof(uint16))
{
auto dst = (uint32*)managedArrayPtr;
auto src = (uint16*)data.Get();
for (int32 i = 0; i < dataCount; i++)
dst[i] = src[i];
}
else
{
Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length());
}
break;
}
}
return result;
}
#endif

View File

@@ -321,6 +321,6 @@ private:
API_FUNCTION(NoProxy) bool UpdateMeshUShort(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj);
API_FUNCTION(NoProxy) bool UpdateTrianglesUInt(int32 triangleCount, MonoArray* trianglesObj);
API_FUNCTION(NoProxy) bool UpdateTrianglesUShort(int32 triangleCount, MonoArray* trianglesObj);
API_FUNCTION(NoProxy) bool DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI);
API_FUNCTION(NoProxy) MonoArray* DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI);
#endif
};

View File

@@ -516,64 +516,12 @@ enum class InternalBufferType
IB32 = 4,
};
void ConvertMeshData(SkinnedMesh* mesh, InternalBufferType type, MonoArray* resultObj, void* srcData)
{
auto vertices = mesh->GetVertexCount();
auto triangles = mesh->GetTriangleCount();
auto indices = triangles * 3;
auto use16BitIndexBuffer = mesh->Use16BitIndexBuffer();
void* managedArrayPtr = mono_array_addr_with_size(resultObj, 0, 0);
switch (type)
{
case InternalBufferType::VB0:
{
Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(VB0SkinnedElementType) * vertices);
break;
}
case InternalBufferType::IB16:
{
if (use16BitIndexBuffer)
{
Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(uint16) * indices);
}
else
{
auto dst = (uint16*)managedArrayPtr;
auto src = (uint32*)srcData;
for (int32 i = 0; i < indices; i++)
{
dst[i] = src[i];
}
}
break;
}
case InternalBufferType::IB32:
{
if (use16BitIndexBuffer)
{
auto dst = (uint32*)managedArrayPtr;
auto src = (uint16*)srcData;
for (int32 i = 0; i < indices; i++)
{
dst[i] = src[i];
}
}
else
{
Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(uint32) * indices);
}
break;
}
}
}
bool SkinnedMesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI)
MonoArray* SkinnedMesh::DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI)
{
SkinnedMesh* mesh = this;
InternalBufferType type = (InternalBufferType)typeI;
auto model = mesh->GetSkinnedModel();
ASSERT(model && resultObj);
ScopeLock lock(model->Locker);
// Virtual assets always fetch from GPU memory
forceGpu |= model->IsVirtual();
@@ -581,23 +529,7 @@ bool SkinnedMesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 type
if (!mesh->IsInitialized() && forceGpu)
{
LOG(Error, "Cannot load mesh data from GPU if it's not loaded.");
return true;
}
if (type == InternalBufferType::IB16 || type == InternalBufferType::IB32)
{
if (mono_array_length(resultObj) != mesh->GetTriangleCount() * 3)
{
LOG(Error, "Invalid buffer size.");
return true;
}
}
else
{
if (mono_array_length(resultObj) != mesh->GetVertexCount())
{
LOG(Error, "Invalid buffer size.");
return true;
}
return nullptr;
}
MeshBufferType bufferType;
@@ -610,37 +542,89 @@ bool SkinnedMesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 type
case InternalBufferType::IB32:
bufferType = MeshBufferType::Index;
break;
default: CRASH;
return true;
default:
return nullptr;
}
BytesContainer data;
int32 dataCount;
if (forceGpu)
{
// Get data from GPU
// TODO: support reusing the input memory buffer to perform a single copy from staging buffer to the input CPU buffer
auto task = mesh->DownloadDataGPUAsync(bufferType, data);
if (task == nullptr)
return true;
return nullptr;
task->Start();
model->Locker.Unlock();
if (task->Wait())
{
LOG(Error, "Task failed.");
return true;
return nullptr;
}
model->Locker.Lock();
// Extract elements count from result data
switch (bufferType)
{
case MeshBufferType::Index:
dataCount = data.Length() / (Use16BitIndexBuffer() ? sizeof(uint16) : sizeof(uint32));
break;
case MeshBufferType::Vertex0:
dataCount = data.Length() / sizeof(VB0SkinnedElementType);
break;
}
}
else
{
// Get data from CPU
int32 count;
if (DownloadDataCPU(bufferType, data, count))
return true;
if (DownloadDataCPU(bufferType, data, dataCount))
return nullptr;
}
// Convert into managed memory
ConvertMeshData(mesh, type, resultObj, data.Get());
return false;
// Convert into managed array
MonoArray* result = mono_array_new(mono_domain_get(), mono_type_get_class(mono_reflection_type_get_type(resultType)), dataCount);
void* managedArrayPtr = mono_array_addr_with_size(result, 0, 0);
const int32 elementSize = data.Length() / dataCount;
switch (type)
{
case InternalBufferType::VB0:
{
Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length());
break;
}
case InternalBufferType::IB16:
{
if (elementSize == sizeof(uint16))
{
Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length());
}
else
{
auto dst = (uint16*)managedArrayPtr;
auto src = (uint32*)data.Get();
for (int32 i = 0; i < dataCount; i++)
dst[i] = src[i];
}
break;
}
case InternalBufferType::IB32:
{
if (elementSize == sizeof(uint16))
{
auto dst = (uint32*)managedArrayPtr;
auto src = (uint16*)data.Get();
for (int32 i = 0; i < dataCount; i++)
dst[i] = src[i];
}
else
{
Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length());
}
break;
}
}
return result;
}
#endif

View File

@@ -199,6 +199,6 @@ private:
#if !COMPILE_WITHOUT_CSHARP
API_FUNCTION(NoProxy) bool UpdateMeshUInt(MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* blendIndicesObj, MonoArray* blendWeightsObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj);
API_FUNCTION(NoProxy) bool UpdateMeshUShort(MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* blendIndicesObj, MonoArray* blendWeightsObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj);
API_FUNCTION(NoProxy) bool DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI);
API_FUNCTION(NoProxy) MonoArray* DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI);
#endif
};

View File

@@ -274,9 +274,8 @@ namespace FlaxEngine
/// <returns>The gathered data.</returns>
public Vertex0[] DownloadVertexBuffer0(bool forceGpu = false)
{
var vertices = VertexCount;
var result = new Vertex0[vertices];
if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB0))
var result = (Vertex0[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(Vertex0), (int)InternalBufferType.VB0);
if (result == null)
throw new Exception("Failed to download mesh data.");
return result;
}
@@ -292,7 +291,7 @@ namespace FlaxEngine
var vb0 = DownloadVertexBuffer0(forceGpu);
var vertices = VertexCount;
var vertices = vb0.Length;
var result = new Vertex[vertices];
for (int i = 0; i < vertices; i++)
{
@@ -319,9 +318,8 @@ namespace FlaxEngine
/// <returns>The gathered data.</returns>
public uint[] DownloadIndexBuffer(bool forceGpu = false)
{
var triangles = TriangleCount;
var result = new uint[triangles * 3];
if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB32))
var result = (uint[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(uint), (int)InternalBufferType.IB32);
if (result == null)
throw new Exception("Failed to download mesh data.");
return result;
}
@@ -334,9 +332,8 @@ namespace FlaxEngine
/// <returns>The gathered data.</returns>
public ushort[] DownloadIndexBufferUShort(bool forceGpu = false)
{
var triangles = TriangleCount;
var result = new ushort[triangles * 3];
if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB16))
var result = (ushort[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(ushort), (int)InternalBufferType.IB16);
if (result == null)
throw new Exception("Failed to download mesh data.");
return result;
}