tvg_saver: optimize binary format.
authorHermet Park <chuneon.park@samsung.com>
Thu, 5 Aug 2021 11:05:03 +0000 (20:05 +0900)
committerHermet Park <chuneon.park@samsung.com>
Mon, 9 Aug 2021 06:35:17 +0000 (15:35 +0900)
Skip to save transform data by accumulating them through the scene tree,
and then applying the final transform to the path points.

Assume that each transform have 36 bytes, it could be increased linear to paints node count
if every paints has transform in the worst case.

Fudamentally, this save their memory and only remains to Bitmap Pictures,
also helps to reduce the loading/rendering workloads since
it doesn't need to perform any transform jobs after converting.

src/examples/images/test.tvg
src/savers/tvg/tvgTvgSaver.cpp
src/savers/tvg/tvgTvgSaver.h

index 5a61851..4ea5404 100644 (file)
Binary files a/src/examples/images/test.tvg and b/src/examples/images/test.tvg differ
index 0ff4db0..2cc46e4 100644 (file)
@@ -36,6 +36,35 @@ static inline TvgBinCounter SERIAL_DONE(TvgBinCounter cnt)
 }
 
 
+static Matrix _multiply(const Matrix* lhs, const Matrix* rhs)
+{
+    Matrix m;
+
+    m.e11 = lhs->e11 * rhs->e11 + lhs->e12 * rhs->e21 + lhs->e13 * rhs->e31;
+    m.e12 = lhs->e11 * rhs->e12 + lhs->e12 * rhs->e22 + lhs->e13 * rhs->e32;
+    m.e13 = lhs->e11 * rhs->e13 + lhs->e12 * rhs->e23 + lhs->e13 * rhs->e33;
+
+    m.e21 = lhs->e21 * rhs->e11 + lhs->e22 * rhs->e21 + lhs->e23 * rhs->e31;
+    m.e22 = lhs->e21 * rhs->e12 + lhs->e22 * rhs->e22 + lhs->e23 * rhs->e32;
+    m.e23 = lhs->e21 * rhs->e13 + lhs->e22 * rhs->e23 + lhs->e23 * rhs->e33;
+
+    m.e31 = lhs->e31 * rhs->e11 + lhs->e32 * rhs->e21 + lhs->e33 * rhs->e31;
+    m.e32 = lhs->e31 * rhs->e12 + lhs->e32 * rhs->e22 + lhs->e33 * rhs->e32;
+    m.e33 = lhs->e31 * rhs->e13 + lhs->e32 * rhs->e23 + lhs->e33 * rhs->e33;
+
+    return m;
+}
+
+
+static void _multiply(Point* pt, const Matrix* transform)
+{
+    auto tx = pt->x * transform->e11 + pt->y * transform->e12 + transform->e13;
+    auto ty = pt->x * transform->e21 + pt->y * transform->e22 + transform->e23;
+    pt->x = tx;
+    pt->y = ty;
+}
+
+
 bool TvgSaver::flushTo(const std::string& path)
 {
     FILE* fp = fopen(path.c_str(), "w+");
@@ -45,7 +74,6 @@ bool TvgSaver::flushTo(const std::string& path)
         fclose(fp);
         return false;
     }
-
     fclose(fp);
 
     return true;
@@ -137,6 +165,19 @@ TvgBinCounter TvgSaver::writeTagProperty(TvgBinTag tag, TvgBinCounter cnt, const
 }
 
 
+TvgBinCounter TvgSaver::writeTransform(const Matrix* transform)
+{
+    if (!transform) return 0;
+
+    if (fabs(transform->e11 - 1) > FLT_EPSILON || fabs(transform->e12) > FLT_EPSILON || fabs(transform->e13) > FLT_EPSILON ||
+        fabs(transform->e21) > FLT_EPSILON || fabs(transform->e22 - 1) > FLT_EPSILON || fabs(transform->e23) > FLT_EPSILON ||
+        fabs(transform->e31) > FLT_EPSILON || fabs(transform->e32) > FLT_EPSILON || fabs(transform->e33 - 1) > FLT_EPSILON) {
+        return writeTagProperty(TVG_TAG_PAINT_TRANSFORM, SIZE(Matrix), transform);
+    }
+    return 0;
+}
+
+
 TvgBinCounter TvgSaver::serializePaint(const Paint* paint)
 {
     TvgBinCounter cnt = 0;
@@ -147,14 +188,6 @@ TvgBinCounter TvgSaver::serializePaint(const Paint* paint)
         cnt += writeTagProperty(TVG_TAG_PAINT_OPACITY, SIZE(opacity), &opacity);
     }
 
-    //transform
-    auto m = const_cast<Paint*>(paint)->transform();
-    if (fabs(m.e11 - 1) > FLT_EPSILON || fabs(m.e12) > FLT_EPSILON || fabs(m.e13) > FLT_EPSILON ||
-        fabs(m.e21) > FLT_EPSILON || fabs(m.e22 - 1) > FLT_EPSILON || fabs(m.e23) > FLT_EPSILON ||
-        fabs(m.e31) > FLT_EPSILON || fabs(m.e32) > FLT_EPSILON || fabs(m.e33 - 1) > FLT_EPSILON) {
-        cnt += writeTagProperty(TVG_TAG_PAINT_TRANSFORM, SIZE(m), &m);
-    }
-
     //composite
     const Paint* cmpTarget = nullptr;
     auto cmpMethod = paint->composite(&cmpTarget);
@@ -166,12 +199,12 @@ TvgBinCounter TvgSaver::serializePaint(const Paint* paint)
 }
 
 
-TvgBinCounter TvgSaver::serializeScene(const Scene* scene)
+TvgBinCounter TvgSaver::serializeScene(const Scene* scene, const Matrix* transform)
 {
     writeTag(TVG_TAG_CLASS_SCENE);
     reserveCount();
 
-    auto cnt = serializeChildren(scene) + serializePaint(scene);
+    auto cnt = serializeChildren(scene, transform) + serializePaint(scene);
 
     writeReservedCount(cnt);
 
@@ -258,7 +291,7 @@ TvgBinCounter TvgSaver::serializeStroke(const Shape* shape)
 }
 
 
-TvgBinCounter TvgSaver::serializePath(const Shape* shape)
+TvgBinCounter TvgSaver::serializePath(const Shape* shape, const Matrix* transform)
 {
     const PathCommand* cmds = nullptr;
     auto cmdCnt = shape->pathCommands(&cmds);
@@ -280,6 +313,15 @@ TvgBinCounter TvgSaver::serializePath(const Shape* shape)
     auto cnt = writeData(&cmdCnt, SIZE(cmdCnt));
     cnt += writeData(&ptsCnt, SIZE(ptsCnt));
     cnt += writeData(outCmds, SIZE(outCmds));
+
+    //transform?
+    if (fabs(transform->e11 - 1) > FLT_EPSILON || fabs(transform->e12) > FLT_EPSILON || fabs(transform->e13) > FLT_EPSILON ||
+        fabs(transform->e21) > FLT_EPSILON || fabs(transform->e22 - 1) > FLT_EPSILON || fabs(transform->e23) > FLT_EPSILON ||
+        fabs(transform->e31) > FLT_EPSILON || fabs(transform->e32) > FLT_EPSILON || fabs(transform->e33 - 1) > FLT_EPSILON) {
+        auto p = const_cast<Point*>(pts);
+        for (uint32_t i = 0; i < ptsCnt; ++i) _multiply(p++, transform);
+    }
+
     cnt += writeData(pts, ptsCnt * SIZE(pts[0]));
 
     writeReservedCount(cnt);
@@ -288,7 +330,7 @@ TvgBinCounter TvgSaver::serializePath(const Shape* shape)
 }
 
 
-TvgBinCounter TvgSaver::serializeShape(const Shape* shape)
+TvgBinCounter TvgSaver::serializeShape(const Shape* shape, const Matrix* transform)
 {
     writeTag(TVG_TAG_CLASS_SHAPE);
     reserveCount();
@@ -315,7 +357,7 @@ TvgBinCounter TvgSaver::serializeShape(const Shape* shape)
         if (color[3] > 0) cnt += writeTagProperty(TVG_TAG_SHAPE_COLOR, SIZE(color), color);
     }
 
-    cnt += serializePath(shape);
+    cnt += serializePath(shape, transform);
     cnt += serializePaint(shape);
 
     writeReservedCount(cnt);
@@ -324,7 +366,7 @@ TvgBinCounter TvgSaver::serializeShape(const Shape* shape)
 }
 
 
-TvgBinCounter TvgSaver::serializePicture(const Picture* picture)
+TvgBinCounter TvgSaver::serializePicture(const Picture* picture, const Matrix* transform)
 {
     writeTag(TVG_TAG_CLASS_PICTURE);
     reserveCount();
@@ -345,9 +387,12 @@ TvgBinCounter TvgSaver::serializePicture(const Picture* picture)
         cnt += writeData(&h, sizeCnt);
         cnt += writeData(pixels, imgSize);
         cnt += SIZE(TvgBinTag) + SIZE(TvgBinCounter);
+
+        //Only Bitmap picture needs the transform info.
+        cnt += writeTransform(transform);
     //Vector Image
     } else {
-        cnt += serializeChildren(picture);
+        cnt += serializeChildren(picture, transform);
     }
 
     cnt += serializePaint(picture);
@@ -366,7 +411,7 @@ TvgBinCounter TvgSaver::serializeComposite(const Paint* cmpTarget, CompositeMeth
     auto flag = static_cast<TvgBinFlag>(cmpMethod);
     auto cnt = writeTagProperty(TVG_TAG_PAINT_CMP_METHOD, SIZE(TvgBinFlag), &flag);
 
-    cnt += serialize(cmpTarget);
+    cnt += serialize(cmpTarget, nullptr);
 
     writeReservedCount(cnt);
 
@@ -374,7 +419,7 @@ TvgBinCounter TvgSaver::serializeComposite(const Paint* cmpTarget, CompositeMeth
 }
 
 
-TvgBinCounter TvgSaver::serializeChildren(const Paint* paint)
+TvgBinCounter TvgSaver::serializeChildren(const Paint* paint, const Matrix* transform)
 {
     auto it = this->iterator(paint);
     if (!it) return 0;
@@ -382,7 +427,7 @@ TvgBinCounter TvgSaver::serializeChildren(const Paint* paint)
     TvgBinCounter cnt = 0;
 
     while (auto p = it->next())
-        cnt += serialize(p);
+        cnt += serialize(p, transform);
 
     delete(it);
 
@@ -390,14 +435,17 @@ TvgBinCounter TvgSaver::serializeChildren(const Paint* paint)
 }
 
 
-TvgBinCounter TvgSaver::serialize(const Paint* paint)
+TvgBinCounter TvgSaver::serialize(const Paint* paint, const Matrix* transform)
 {
     if (!paint) return 0;
 
+    auto m = const_cast<Paint*>(paint)->transform();
+    if (transform) m = _multiply(transform, &m);
+
     switch (paint->id()) {
-        case TVG_CLASS_ID_SHAPE: return serializeShape(static_cast<const Shape*>(paint));
-        case TVG_CLASS_ID_SCENE: return serializeScene(static_cast<const Scene*>(paint));
-        case TVG_CLASS_ID_PICTURE: return serializePicture(static_cast<const Picture*>(paint));
+        case TVG_CLASS_ID_SHAPE: return serializeShape(static_cast<const Shape*>(paint), &m);
+        case TVG_CLASS_ID_SCENE: return serializeScene(static_cast<const Scene*>(paint), &m);
+        case TVG_CLASS_ID_PICTURE: return serializePicture(static_cast<const Picture*>(paint), &m);
     }
 
     return 0;
@@ -407,7 +455,7 @@ TvgBinCounter TvgSaver::serialize(const Paint* paint)
 void TvgSaver::run(unsigned tid)
 {
     if (!writeHeader()) return;
-    if (serialize(paint) == 0) return;
+    if (serialize(paint, nullptr) == 0) return;
     if (!flushTo(path)) return;
 }
 
@@ -457,4 +505,4 @@ bool TvgSaver::save(Paint* paint, const string& path)
     TaskScheduler::request(this);
 
     return true;
-}
\ No newline at end of file
+}
index 6f800ee..fb8190b 100644 (file)
@@ -47,17 +47,18 @@ private:
     void writeReservedCount(TvgBinCounter cnt);
     TvgBinCounter writeData(const void* data, TvgBinCounter cnt);
     TvgBinCounter writeTagProperty(TvgBinTag tag, TvgBinCounter cnt, const void* data);
+    TvgBinCounter writeTransform(const Matrix* transform);
 
-    TvgBinCounter serialize(const Paint* paint);
+    TvgBinCounter serialize(const Paint* paint, const Matrix* transform);
+    TvgBinCounter serializeScene(const Scene* scene, const Matrix* transform);
+    TvgBinCounter serializeShape(const Shape* shape, const Matrix* transform);
+    TvgBinCounter serializePicture(const Picture* picture, const Matrix* transform);
     TvgBinCounter serializePaint(const Paint* paint);
-    TvgBinCounter serializeScene(const Scene* scene);
-    TvgBinCounter serializeShape(const Shape* shape);
-    TvgBinCounter serializePicture(const Picture* picture);
     TvgBinCounter serializeFill(const Fill* fill, TvgBinTag tag);
     TvgBinCounter serializeStroke(const Shape* shape);
-    TvgBinCounter serializePath(const Shape* shape);
+    TvgBinCounter serializePath(const Shape* shape, const Matrix* transform);
     TvgBinCounter serializeComposite(const Paint* cmpTarget, CompositeMethod cmpMethod);
-    TvgBinCounter serializeChildren(const Paint* paint);
+    TvgBinCounter serializeChildren(const Paint* paint, const Matrix* transform);
 
 public:
     ~TvgSaver();