| 786 | } |
| 787 | |
| 788 | bool MeshBase::DownloadData(Span<MeshBufferType> types, Array<BytesContainer, FixedAllocation<4>>& buffers, Array<GPUVertexLayout*, FixedAllocation<4>>& layouts, bool forceGpu) const |
| 789 | { |
| 790 | PROFILE_CPU(); |
| 791 | buffers.Resize(types.Length()); |
| 792 | layouts.Resize(types.Length()); |
| 793 | layouts.SetAll(nullptr); |
| 794 | auto model = _model; |
| 795 | model->Locker.Lock(); |
| 796 | |
| 797 | // Virtual assets always fetch from GPU memory |
| 798 | forceGpu |= model->IsVirtual(); |
| 799 | |
| 800 | if (forceGpu) |
| 801 | { |
| 802 | if (!IsInitialized()) |
| 803 | { |
| 804 | model->Locker.Unlock(); |
| 805 | LOG(Error, "Cannot load mesh data from GPU if it's not loaded."); |
| 806 | return true; |
| 807 | } |
| 808 | |
| 809 | // Get data from GPU (start of series of async tasks that copy GPU-read data into staging buffers) |
| 810 | Array<Task*, FixedAllocation<(int32)MeshBufferType::MAX>> tasks; |
| 811 | for (int32 i = 0; i < types.Length(); i++) |
| 812 | { |
| 813 | auto task = DownloadDataGPUAsync(types[i], buffers[i], &layouts[i]); |
| 814 | if (!task) |
| 815 | { |
| 816 | model->Locker.Unlock(); |
| 817 | return true; |
| 818 | } |
| 819 | task->Start(); |
| 820 | tasks.Add(task); |
| 821 | } |
| 822 | |
| 823 | // Wait for async tasks |
| 824 | model->Locker.Unlock(); |
| 825 | if (Task::WaitAll(tasks)) |
| 826 | { |
| 827 | LOG(Error, "Failed to download mesh data from GPU."); |
| 828 | return true; |
| 829 | } |
| 830 | model->Locker.Lock(); |
| 831 | } |
| 832 | else |
| 833 | { |
| 834 | // Get data from CPU |
| 835 | for (int32 i = 0; i < types.Length(); i++) |
| 836 | { |
| 837 | int32 count = 0; |
| 838 | if (DownloadDataCPU(types[i], buffers[i], count, &layouts[i])) |
| 839 | { |
| 840 | model->Locker.Unlock(); |
| 841 | return true; |
| 842 | } |
| 843 | } |
| 844 | } |
| 845 | |