[flutter] Batching of render commands.

This commit is contained in:
Mario Zechner 2022-11-23 11:47:52 +01:00
parent bd7ec75749
commit 4e8ca9c46f
4 changed files with 89 additions and 34 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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) {