diff --git a/Source/Engine/Graphics/Mesh.cs b/Source/Engine/Graphics/Mesh.cs index d4f693e77..0a986d44d 100644 --- a/Source/Engine/Graphics/Mesh.cs +++ b/Source/Engine/Graphics/Mesh.cs @@ -527,9 +527,8 @@ namespace FlaxEngine /// The gathered data. 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 /// The gathered data. 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 /// The gathered data. 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 /// The gathered data. 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; } diff --git a/Source/Engine/Graphics/Models/Mesh.cpp b/Source/Engine/Graphics/Models/Mesh.cpp index 7b0130874..335b4cb69 100644 --- a/Source/Engine/Graphics/Models/Mesh.cpp +++ b/Source/Engine/Graphics/Models/Mesh.cpp @@ -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 diff --git a/Source/Engine/Graphics/Models/Mesh.h b/Source/Engine/Graphics/Models/Mesh.h index ee16c16e3..9b1ab4846 100644 --- a/Source/Engine/Graphics/Models/Mesh.h +++ b/Source/Engine/Graphics/Models/Mesh.h @@ -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 }; diff --git a/Source/Engine/Graphics/Models/SkinnedMesh.cpp b/Source/Engine/Graphics/Models/SkinnedMesh.cpp index 89db8ff8b..f33b8b4fd 100644 --- a/Source/Engine/Graphics/Models/SkinnedMesh.cpp +++ b/Source/Engine/Graphics/Models/SkinnedMesh.cpp @@ -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 diff --git a/Source/Engine/Graphics/Models/SkinnedMesh.h b/Source/Engine/Graphics/Models/SkinnedMesh.h index 8bf957554..57a382cff 100644 --- a/Source/Engine/Graphics/Models/SkinnedMesh.h +++ b/Source/Engine/Graphics/Models/SkinnedMesh.h @@ -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 }; diff --git a/Source/Engine/Graphics/SkinnedMesh.cs b/Source/Engine/Graphics/SkinnedMesh.cs index 5998c6a1e..8fb7a83dc 100644 --- a/Source/Engine/Graphics/SkinnedMesh.cs +++ b/Source/Engine/Graphics/SkinnedMesh.cs @@ -274,9 +274,8 @@ namespace FlaxEngine /// The gathered data. 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 /// The gathered data. 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 /// The gathered data. 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; }