aboutsummaryrefslogtreecommitdiff
path: root/sdk/lowlevel/source/NvBlastFamily.cpp
blob: 1f517b15b34b467b204df9a0e6babd1e150af7c2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
/*
* Copyright (c) 2016-2017, NVIDIA CORPORATION.  All rights reserved.
*
* NVIDIA CORPORATION and its licensors retain all intellectual property
* and proprietary rights in and to this software, related documentation
* and any modifications thereto.  Any use, reproduction, disclosure or
* distribution of this software and related documentation without an express
* license agreement from NVIDIA CORPORATION is strictly prohibited.
*/


#include "NvBlastFamily.h"
#include "NvBlastFamilyGraph.h"
#include "NvBlastIndexFns.h"

#include <new>

namespace Nv
{
namespace Blast
{

//////// Global functions ////////

struct FamilyDataOffsets
{
	size_t m_actors;
	size_t m_visibleChunkIndexLinks;
	size_t m_chunkActorIndices;
	size_t m_graphNodeIndexLinks;
	size_t m_lowerSupportChunkHealths;
	size_t m_graphBondHealths;
	size_t m_familyGraph;
};


static size_t createFamilyDataOffsets(FamilyDataOffsets& offsets, const Asset* asset)
{
	const Nv::Blast::SupportGraph& graph = asset->m_graph;

	NvBlastCreateOffsetStart(sizeof(FamilyHeader));
	NvBlastCreateOffsetAlign16(offsets.m_actors, asset->getLowerSupportChunkCount() * sizeof(Actor));
	NvBlastCreateOffsetAlign16(offsets.m_visibleChunkIndexLinks, asset->m_chunkCount * sizeof(IndexDLink<uint32_t>));
	NvBlastCreateOffsetAlign16(offsets.m_chunkActorIndices, asset->getUpperSupportChunkCount() * sizeof(uint32_t));
	NvBlastCreateOffsetAlign16(offsets.m_graphNodeIndexLinks, graph.m_nodeCount * sizeof(uint32_t));
	NvBlastCreateOffsetAlign16(offsets.m_lowerSupportChunkHealths, asset->getLowerSupportChunkCount() * sizeof(float));
	NvBlastCreateOffsetAlign16(offsets.m_graphBondHealths, asset->getBondCount() * sizeof(float));
	NvBlastCreateOffsetAlign16(offsets.m_familyGraph, static_cast<size_t>(FamilyGraph::requiredMemorySize(graph.m_nodeCount, asset->getBondCount())));
	return NvBlastCreateOffsetEndAlign16();
}


size_t getFamilyMemorySize(const Asset* asset)
{
#if NVBLAST_CHECK_PARAMS
	if (asset == nullptr)
	{
		NVBLAST_ALWAYS_ASSERT();
		return 0;
	}
#endif

	FamilyDataOffsets offsets;
	return createFamilyDataOffsets(offsets, asset);
}


NvBlastFamily* createFamily(void* mem, const NvBlastAsset* asset, NvBlastLog logFn)
{
	NVBLAST_CHECK(mem != nullptr, logFn, "createFamily: NULL mem pointer input.", return nullptr);
	NVBLAST_CHECK(asset != nullptr, logFn, "createFamily: NULL asset pointer input.", return nullptr);

	NVBLAST_CHECK((reinterpret_cast<uintptr_t>(mem) & 0xF) == 0, logFn, "createFamily: mem pointer not 16-byte aligned.", return nullptr);

	const Asset& solverAsset = *static_cast<const Asset*>(asset);

	if (solverAsset.m_chunkCount == 0)
	{
		NVBLAST_LOG_ERROR(logFn, "createFamily: Asset has no chunks.  Family not created.\n");
		return nullptr;
	}

	const Nv::Blast::SupportGraph& graph = solverAsset.m_graph;

	const uint32_t bondCount = solverAsset.getBondCount();

	// We need to keep this many actor representations around for our island indexing scheme.
	const uint32_t lowerSupportChunkCount = solverAsset.getLowerSupportChunkCount();

	// We need this many chunk actor indices.
	const uint32_t upperSupportChunkCount = solverAsset.getUpperSupportChunkCount();

	// Family offsets
	FamilyDataOffsets offsets;
	const size_t dataSize = createFamilyDataOffsets(offsets, &solverAsset);

	// Restricting our data size to < 4GB so that we may use uint32_t offsets
	if (dataSize > (size_t)UINT32_MAX)
	{
		NVBLAST_LOG_ERROR(logFn, "Nv::Blast::Actor::instanceAllocate: Instance data block size will exceed 4GB.  Instance not created.\n");
		return nullptr;
	}

	// Allocate family
	NvBlastFamily* family = (NvBlastFamily*)mem;

	// Fill in family header
	FamilyHeader* header = (FamilyHeader*)family;
	header->dataType = NvBlastDataBlock::FamilyDataBlock;
	header->formatVersion = NvBlastFamilyDataFormat::Current;
	header->size = (uint32_t)dataSize;
	header->m_assetID = solverAsset.m_ID;
	header->m_actorCount = 0;
	header->m_actorsOffset = (uint32_t)offsets.m_actors;
	header->m_visibleChunkIndexLinksOffset = (uint32_t)offsets.m_visibleChunkIndexLinks;
	header->m_chunkActorIndicesOffset = (uint32_t)offsets.m_chunkActorIndices;
	header->m_graphNodeIndexLinksOffset = (uint32_t)offsets.m_graphNodeIndexLinks;
	header->m_lowerSupportChunkHealthsOffset = (uint32_t)offsets.m_lowerSupportChunkHealths;
	header->m_graphBondHealthsOffset = (uint32_t)offsets.m_graphBondHealths;
	header->m_familyGraphOffset = (uint32_t)offsets.m_familyGraph;

	// Runtime data
	header->m_asset = &solverAsset;	// NOTE: this should be resolved from m_assetID

	// Initialize family header data:

	// Actors - initialize to defaults, with zero offset value (indicating inactive state)
	Actor* actors = header->getActors();	// This will get the subsupport actors too
	for (uint32_t i = 0; i < lowerSupportChunkCount; ++i)
	{
		new (actors + i) Actor();
	}

	// Visible chunk index links - initialize to solitary links (0xFFFFFFFF fields)
	memset(header->getVisibleChunkIndexLinks(), 0xFF, solverAsset.m_chunkCount*sizeof(IndexDLink<uint32_t>));

	// Chunk actor IDs - initialize to invalid (0xFFFFFFFF)
	memset(header->getChunkActorIndices(), 0xFF, upperSupportChunkCount*sizeof(uint32_t));

	// Graph node index links - initialize to solitary links
	memset(header->getGraphNodeIndexLinks(), 0xFF, graph.m_nodeCount*sizeof(uint32_t));

	// Healths are initialized to 0
	memset(header->getLowerSupportChunkHealths(), 0, lowerSupportChunkCount*sizeof(float));
	memset(header->getBondHealths(), 0, bondCount*sizeof(float));

	// FamilyGraph ctor
	new (header->getFamilyGraph()) FamilyGraph(&graph);

	return family;
}

} // namespace Blast
} // namespace Nv


// API implementation

extern "C"
{

NvBlastFamily* NvBlastAssetCreateFamily(void* mem, const NvBlastAsset* asset, NvBlastLog logFn)
{
	return Nv::Blast::createFamily(mem, asset, logFn);
}


uint32_t NvBlastFamilyGetFormatVersion(const NvBlastFamily* family, NvBlastLog logFn)
{
	NVBLAST_CHECK(family != nullptr, logFn, "NvBlastFamilyGetFormatVersion: NULL family pointer input.", return UINT32_MAX);
	return reinterpret_cast<const Nv::Blast::FamilyHeader*>(family)->formatVersion;
}


void NvBlastFamilySetAsset(NvBlastFamily* family, const NvBlastAsset* asset, NvBlastLog logFn)
{
	NVBLAST_CHECK(family != nullptr, logFn, "NvBlastFamilySetAsset: NULL family pointer input.", return);
	NVBLAST_CHECK(asset != nullptr, logFn, "NvBlastFamilySetAsset: NULL asset pointer input.", return);

	Nv::Blast::FamilyHeader* header = reinterpret_cast<Nv::Blast::FamilyHeader*>(family);
	const Nv::Blast::Asset* solverAsset = reinterpret_cast<const Nv::Blast::Asset*>(asset);

	if (memcmp(&header->m_assetID, &solverAsset->m_ID, sizeof(NvBlastID)))
	{
		NVBLAST_LOG_ERROR(logFn, "NvBlastFamilySetAsset: wrong asset.  Passed asset ID doesn't match family asset ID.");
		return;
	}

	header->m_asset = solverAsset;
}


uint32_t NvBlastFamilyGetSize(const NvBlastFamily* family, NvBlastLog logFn)
{
	NVBLAST_CHECK(family != nullptr, logFn, "NvBlastFamilyGetSize: NULL family pointer input.", return 0);
	return reinterpret_cast<const Nv::Blast::FamilyHeader*>(family)->size;
}


NvBlastID NvBlastFamilyGetAssetID(const NvBlastFamily* family, NvBlastLog logFn)
{
	NVBLAST_CHECK(family != nullptr, logFn, "NvBlastFamilyGetAssetID: NULL family pointer input.", return NvBlastID());
	return reinterpret_cast<const Nv::Blast::FamilyHeader*>(family)->m_assetID;
}


uint32_t NvBlastFamilyGetActorCount(const NvBlastFamily* family, NvBlastLog logFn)
{
	NVBLAST_CHECK(family != nullptr, logFn, "NvBlastFamilyGetActorCount: NULL family pointer input.", return 0);

	const Nv::Blast::FamilyHeader* header = reinterpret_cast<const Nv::Blast::FamilyHeader*>(family);

	if (header->formatVersion != NvBlastFamilyDataFormat::Current)
	{
		NVBLAST_LOG_ERROR(logFn, "NvBlastFamilyGetActorCount: wrong family format.  Family must be converted to current version.");
		return 0;
	}

	return header->m_actorCount;
}


uint32_t NvBlastFamilyGetActors(NvBlastActor** actors, uint32_t actorsSize, const NvBlastFamily* family, NvBlastLog logFn)
{
	NVBLAST_CHECK(actors != nullptr, logFn, "NvBlastFamilyGetActors: NULL actors pointer input.", return 0);
	NVBLAST_CHECK(family != nullptr, logFn, "NvBlastFamilyGetActors: NULL family pointer input.", return 0);

	const Nv::Blast::FamilyHeader* header = reinterpret_cast<const Nv::Blast::FamilyHeader*>(family);

	if (header->formatVersion != NvBlastFamilyDataFormat::Current)
	{
		NVBLAST_LOG_ERROR(logFn, "NvBlastFamilyGetActors: wrong family format.  Family must be converted to current version.");
		return 0;
	}

	// Iterate through active actors and write to supplied array
	const uint32_t familyActorCount = header->getActorBufferSize();
	Nv::Blast::Actor* familyActor = header->getActors();
	uint32_t actorCount = 0;
	for (uint32_t i = 0; actorCount < actorsSize && i < familyActorCount; ++i, ++familyActor)
	{
		if (familyActor->isActive())
		{
			actors[actorCount++] = familyActor;
		}
	}

	return actorCount;
}


NvBlastActor* NvBlastFamilyGetChunkActor(const NvBlastFamily* family, uint32_t chunkIndex, NvBlastLog logFn)
{
	NVBLAST_CHECK(family != nullptr, logFn, "NvBlastFamilyGetChunkActor: NULL family pointer input.", return nullptr);

	const Nv::Blast::FamilyHeader* header = reinterpret_cast<const Nv::Blast::FamilyHeader*>(family);

	NVBLAST_CHECK(header->m_asset != nullptr, logFn, "NvBlastFamilyGetChunkActor: NvBlastFamily has null asset set.", return nullptr);

	const Nv::Blast::Asset& solverAsset = *static_cast<const Nv::Blast::Asset*>(header->m_asset);
	NVBLAST_CHECK(chunkIndex < solverAsset.m_chunkCount, logFn, "NvBlastFamilyGetChunkActor: bad value of chunkIndex for the given family's asset.", return nullptr);

	// get actorIndex from chunkIndex
	uint32_t actorIndex;
	if (chunkIndex < solverAsset.getUpperSupportChunkCount())
	{
		actorIndex = header->getChunkActorIndices()[chunkIndex];
	}
	else
	{
		actorIndex = chunkIndex - (solverAsset.getUpperSupportChunkCount() - solverAsset.m_graph.m_nodeCount);
	}

	// get actor from actorIndex
	if (!Nv::Blast::isInvalidIndex(actorIndex))
	{
		NVBLAST_ASSERT(actorIndex < header->getActorBufferSize());
		Nv::Blast::Actor* actor = &header->getActors()[actorIndex];
		if (actor->isActive())
		{
			return actor;
		}
	}
	return nullptr;
}


uint32_t NvBlastFamilyGetMaxActorCount(const NvBlastFamily* family, NvBlastLog logFn)
{
	NVBLAST_CHECK(family != nullptr, logFn, "NvBlastFamilyGetMaxActorCount: NULL family pointer input.", return 0);
	const Nv::Blast::FamilyHeader* header = reinterpret_cast<const Nv::Blast::FamilyHeader*>(family);
	return header->getActorBufferSize();
}

} // extern "C"