Forráskód Böngészése

[flutter] Batching of render commands.

Mario Zechner 2 éve
szülő
commit
4e8ca9c46f

+ 1 - 1
spine-flutter/example/lib/flame_example.dart

@@ -116,7 +116,7 @@ class PreloadAndShareSpineDataExample extends FlameGame {
     // gets their own SkeletonDrawable copy derived from the cached data. The
     // SkeletonDrawable copies do not own the underlying skeleton data and atlas.
     final rng = Random();
-    for (int i = 0; i < 50; i++) {
+    for (int i = 0; i < 100; i++) {
       final drawable = SkeletonDrawable(cachedAtlas, cachedSkeletonData, false);
       final scale = 0.1 + rng.nextDouble() * 0.2;
       final position = Vector2(rng.nextDouble() * size.x, rng.nextDouble() * size.y);

BIN
spine-flutter/lib/assets/libspine_flutter.wasm


+ 2 - 2
spine-flutter/lib/spine_flutter.dart

@@ -3342,8 +3342,8 @@ class RenderCommand {
       // https://github.com/flutter/engine/blob/5c60785b802ad2c8b8899608d949342d5c624952/lib/ui/painting/vertices.cc#L21
       vertices = Vertices.raw(VertexMode.triangles, positions,
           textureCoordinates: uvs,
-          colors: _bindings.spine_render_command_get_colors(nativeCmd).asTypedList(numVertices),
-          indices: _bindings.spine_render_command_get_indices(nativeCmd).asTypedList(numIndices));
+          colors: colors,
+          indices: indices);
     } else {
       // On the web, rendering is done through CanvasKit, which requires copies of the native data.
       final positionsCopy = Float32List.fromList(positions);

+ 86 - 31
spine-flutter/src/spine_flutter.cpp

@@ -49,7 +49,6 @@ struct Block {
 
 	uint8_t* allocate(int numBytes) {
 		uint8_t *ptr = memory + allocated;
-		memset(ptr, 0, numBytes);
 		allocated += numBytes;
 		return ptr;
 	}
@@ -150,14 +149,25 @@ typedef struct _spine_vector {
 	float x, y;
 } _spine_vector;
 
-typedef struct _spine_skeleton_drawable {
+typedef struct _spine_skeleton_drawable : public SpineObject {
 	spine_skeleton skeleton;
 	spine_animation_state animationState;
 	spine_animation_state_data animationStateData;
 	spine_animation_state_events animationStateEvents;
 	void *clipping;
-	_spine_render_command *renderCommand;
 	BlockAllocator *allocator;
+	Vector<float> worldVertices;
+	Vector<unsigned short> quadIndices;
+	Vector<_spine_render_command *> renderCommands;
+
+	_spine_skeleton_drawable() {
+		quadIndices.add(0);
+		quadIndices.add(1);
+		quadIndices.add(2);
+		quadIndices.add(2);
+		quadIndices.add(3);
+		quadIndices.add(0);
+	}
 } _spine_skeleton_drawable;
 
 typedef struct _spine_skin_entry {
@@ -619,7 +629,7 @@ static _spine_render_command *spine_render_command_create(BlockAllocator &alloca
 // SkeletonDrawable
 
 spine_skeleton_drawable spine_skeleton_drawable_create(spine_skeleton_data skeletonData) {
-	_spine_skeleton_drawable *drawable = SpineExtension::calloc<_spine_skeleton_drawable>(1, __FILE__, __LINE__);
+	_spine_skeleton_drawable *drawable = new (__FILE__, __LINE__) _spine_skeleton_drawable();
 	drawable->skeleton = (spine_skeleton) new (__FILE__, __LINE__) Skeleton((SkeletonData *) skeletonData);
 	AnimationStateData *stateData = new (__FILE__, __LINE__) AnimationStateData((SkeletonData *) skeletonData);
 	drawable->animationStateData = (spine_animation_state_data) stateData;
@@ -646,25 +656,76 @@ void spine_skeleton_drawable_dispose(spine_skeleton_drawable drawable) {
 	SpineExtension::free(drawable, __FILE__, __LINE__);
 }
 
+static _spine_render_command *batch_sub_commands(BlockAllocator &allocator, Vector<_spine_render_command*> &commands, int first, int last, int numVertices, int numIndices) {
+	_spine_render_command *batched = spine_render_command_create(allocator, numVertices, numIndices, commands[0]->blendMode, commands[0]->atlasPage);
+	float *positions = batched->positions;
+	float *uvs = batched->uvs;
+	int32_t *colors = batched->colors;
+	uint16_t *indices = batched->indices;
+	int indicesOffset = 0;
+	for (int i = first; i <= last; i++) {
+		_spine_render_command *cmd = commands[i];
+		memcpy(positions, cmd->positions, sizeof(float) * 2 * cmd->numVertices);
+		memcpy(uvs, cmd->uvs, sizeof(float) * 2 * cmd->numVertices);
+		memcpy(colors, cmd->colors, sizeof(int32_t) * cmd->numVertices);
+		for (int ii = 0; ii < cmd->numIndices; ii++)
+			indices[ii] = cmd->indices[ii] + indicesOffset;
+		indicesOffset += cmd->numVertices;
+		positions += 2 * cmd->numVertices;
+		uvs += 2 * cmd->numVertices;
+		colors += cmd->numVertices;
+		indices += cmd->numIndices;
+	}
+	return batched;
+}
+
+static _spine_render_command *batch_commands(BlockAllocator &allocator, Vector<_spine_render_command*> &commands) {
+	if (commands.size() == 0) return nullptr;
+
+	_spine_render_command *root = nullptr;
+	_spine_render_command *last = nullptr;
+
+	_spine_render_command *first = commands[0];
+	int startIndex = 0;
+	int i = 1;
+	int numVertices = first->numVertices;
+	int numIndices = first->numIndices;
+	while (i <= commands.size()) {
+		_spine_render_command *cmd = i < commands.size() ? commands[i] : nullptr;
+		if (cmd != nullptr && cmd->atlasPage == first->atlasPage &&
+			cmd->blendMode == first->blendMode &&
+			numIndices + cmd->numIndices < 0xffff) {
+			numVertices += cmd->numVertices;
+			numIndices += cmd->numIndices;
+		} else {
+			_spine_render_command *batched = batch_sub_commands(allocator, commands, startIndex, i - 1, numVertices, numIndices);
+			if (!last) {
+				root = last = batched;
+			} else {
+				last->next = batched;
+				last = batched;
+			}
+			if (i == commands.size()) break;
+			first = commands[i];
+			startIndex = i;
+			numVertices = first->numVertices;
+			numIndices = first->numIndices;
+		}
+		i++;
+	}
+	return root;
+}
+
 spine_render_command spine_skeleton_drawable_render(spine_skeleton_drawable drawable) {
 	_spine_skeleton_drawable *_drawable = (_spine_skeleton_drawable *) drawable;
 	if (!_drawable) return nullptr;
 	if (!_drawable->skeleton) return nullptr;
 
 	_drawable->allocator->compress();
-	_drawable->renderCommand = nullptr;
+	_drawable->renderCommands.clear();
 
-	Vector<unsigned short> quadIndices;
-	quadIndices.add(0);
-	quadIndices.add(1);
-	quadIndices.add(2);
-	quadIndices.add(2);
-	quadIndices.add(3);
-	quadIndices.add(0);
-	Vector<float> worldVertices;
 	SkeletonClipping &clipper = *(SkeletonClipping *) _drawable->clipping;
 	Skeleton *skeleton = (Skeleton *) _drawable->skeleton;
-	_spine_render_command *lastCommand = nullptr;
 
 	for (unsigned i = 0; i < skeleton->getSlots().size(); ++i) {
 		Slot &slot = *skeleton->getDrawOrder()[i];
@@ -677,7 +738,9 @@ spine_render_command spine_skeleton_drawable_render(spine_skeleton_drawable draw
 			continue;
 		}
 
-		Vector<float> *vertices = &worldVertices;
+		Vector<float> *worldVertices = &_drawable->worldVertices;
+		Vector<unsigned short> *quadIndices = &_drawable->quadIndices;
+		Vector<float> *vertices = worldVertices;
 		int32_t verticesCount;
 		Vector<float> *uvs;
 		Vector<unsigned short> *indices;
@@ -695,11 +758,11 @@ spine_render_command spine_skeleton_drawable_render(spine_skeleton_drawable draw
 				continue;
 			}
 
-			worldVertices.setSize(8, 0);
-			regionAttachment->computeWorldVertices(slot, worldVertices, 0, 2);
+			worldVertices->setSize(8, 0);
+			regionAttachment->computeWorldVertices(slot, *worldVertices, 0, 2);
 			verticesCount = 4;
 			uvs = &regionAttachment->getUVs();
-			indices = &quadIndices;
+			indices = quadIndices;
 			indicesCount = 6;
 			pageIndex = ((AtlasRegion *) regionAttachment->getRegion())->page->index;
 
@@ -713,8 +776,8 @@ spine_render_command spine_skeleton_drawable_render(spine_skeleton_drawable draw
 				continue;
 			}
 
-			worldVertices.setSize(mesh->getWorldVerticesLength(), 0);
-			mesh->computeWorldVertices(slot, 0, mesh->getWorldVerticesLength(), worldVertices.buffer(), 0, 2);
+			worldVertices->setSize(mesh->getWorldVerticesLength(), 0);
+			mesh->computeWorldVertices(slot, 0, mesh->getWorldVerticesLength(), worldVertices->buffer(), 0, 2);
 			verticesCount = (int32_t) (mesh->getWorldVerticesLength() >> 1);
 			uvs = &mesh->getUVs();
 			indices = &mesh->getTriangles();
@@ -735,7 +798,7 @@ spine_render_command spine_skeleton_drawable_render(spine_skeleton_drawable draw
 		uint32_t color = (a << 24) | (r << 16) | (g << 8) | b;
 
 		if (clipper.isClipping()) {
-			clipper.clipTriangles(worldVertices, *indices, *uvs, 2);
+			clipper.clipTriangles(*worldVertices, *indices, *uvs, 2);
 			vertices = &clipper.getClippedVertices();
 			verticesCount = (int32_t) (clipper.getClippedVertices().size() >> 1);
 			uvs = &clipper.getClippedUVs();
@@ -744,24 +807,16 @@ spine_render_command spine_skeleton_drawable_render(spine_skeleton_drawable draw
 		}
 
 		_spine_render_command *cmd = spine_render_command_create(*_drawable->allocator, verticesCount, indicesCount, (spine_blend_mode) slot.getData().getBlendMode(), pageIndex);
-
+		_drawable->renderCommands.add(cmd);
 		memcpy(cmd->positions, vertices->buffer(), (verticesCount << 1) * sizeof(float));
 		memcpy(cmd->uvs, uvs->buffer(), (verticesCount << 1) * sizeof(float));
 		for (int ii = 0; ii < verticesCount; ii++) cmd->colors[ii] = color;
 		memcpy(cmd->indices, indices->buffer(), indices->size() * sizeof(uint16_t));
-
-		if (!lastCommand) {
-			_drawable->renderCommand = lastCommand = cmd;
-		} else {
-			lastCommand->next = cmd;
-			lastCommand = cmd;
-		}
-
 		clipper.clipEnd(slot);
 	}
 	clipper.clipEnd();
 
-	return (spine_render_command) _drawable->renderCommand;
+	return (spine_render_command) batch_commands(*_drawable->allocator, _drawable->renderCommands);
 }
 
 spine_skeleton spine_skeleton_drawable_get_skeleton(spine_skeleton_drawable drawable) {