implement rle raster. 67/230567/7
authorHermet Park <chuneon.park@samsung.com>
Sat, 11 Apr 2020 06:23:37 +0000 (15:23 +0900)
committerHermet Park <chuneon.park@samsung.com>
Mon, 13 Apr 2020 04:42:24 +0000 (13:42 +0900)
Change-Id: Ie21dfbf0ff1aed43bfa750eeef3b8c033a986416

src/lib/gl_engine/tvgGlRaster.cpp
src/lib/gl_engine/tvgGlRaster.h
src/lib/sw_engine/meson.build
src/lib/sw_engine/tvgSwCommon.h
src/lib/sw_engine/tvgSwRaster.cpp
src/lib/sw_engine/tvgSwRaster.h
src/lib/sw_engine/tvgSwRle.cpp [new file with mode: 0644]
src/lib/sw_engine/tvgSwShape.cpp
src/lib/tvgCommon.h
src/lib/tvgShapeNode.cpp

index c3bb407..50ed465 100644 (file)
@@ -29,7 +29,7 @@ struct GlShape
 };
 
 
-void* GlRaster::prepare(const ShapeNode& shape, void* data)
+void* GlRaster::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
 {
     //prepare shape data
     GlShape* sdata = static_cast<GlShape*>(data);
index d6da2fe..08f750c 100644 (file)
@@ -23,7 +23,7 @@ namespace tvg
 class GlRaster : public RasterMethod
 {
 public:
-    void* prepare(const ShapeNode& shape, void* data) override;
+    void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override;
     static GlRaster* inst();
     static int init();
     static int term();
index df72f38..4937d59 100644 (file)
@@ -3,6 +3,7 @@ source_file = [
    'tvgSwRaster.h',
    'tvgSwRaster.cpp',
    'tvgSwShape.cpp',
+   'tvgSwRle.cpp',
 ]
 
 swraster_dep = declare_dependency(
index a153102..2269cfb 100644 (file)
 #include "tvgCommon.h"
 
 using namespace tvg;
+using SwPoint = Point;
 
+constexpr auto SW_CURVE_TAG_CONIC = 0;
 constexpr auto SW_CURVE_TAG_ON = 1;
 constexpr auto SW_CURVE_TAG_CUBIC = 2;
 
 struct SwOutline
 {
-  size_t*     cntrs;            //the contour end points
-  size_t      cntrsCnt;         //number of contours in glyph
-  size_t      reservedCntrsCnt;
-  Point*      pts;              //the outline's points
-  size_t      ptsCnt;           //number of points in the glyph
-  size_t      reservedPtsCnt;
-  char*       tags;             //the points flags
-  size_t      flags;            //outline masks
+    size_t*     cntrs;            //the contour end points
+    size_t      cntrsCnt;         //number of contours in glyph
+    size_t      reservedCntrsCnt;
+    SwPoint*    pts;              //the outline's points
+    size_t      ptsCnt;           //number of points in the glyph
+    size_t      reservedPtsCnt;
+    char*       tags;             //the points flags
+    size_t      flags;            //outline masks
+};
+
+struct SwSpan
+{
+    size_t x;
+    size_t y;
+    size_t len;
+    uint8_t coverage;
+};
+
+struct SwRleData
+{
+    size_t alloc;
+    size_t size;
+    SwSpan *spans;
+};
+
+struct SwBBox
+{
+    size_t xMin, yMin;
+    size_t xMax, yMax;
 };
 
 struct SwShape
 {
-//    SwRleRaster raster;
     SwOutline*   outline;
+    SwRleData    rle;
+    SwBBox       bbox;
 };
 
 bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata);
 void shapeDelOutline(const ShapeNode& shape, SwShape& sdata);
 bool shapeGenRle(const ShapeNode& shape, SwShape& sdata);
-bool shapeUpdateBBox(const ShapeNode& shape, SwShape& sdata);
+void shapeDelRle(const ShapeNode& shape, SwShape& sdata);
+bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata);
+
+bool rleRender(SwShape& sdata);
 
 #endif /* _TVG_SW_COMMON_H_ */
index a1afdda..a7d2928 100644 (file)
 
 static SwRaster* pInst = nullptr;
 
+
 /************************************************************************/
 /* External Class Implementation                                        */
 /************************************************************************/
 
-void* SwRaster::prepare(const ShapeNode& shape, void* data)
+void* SwRaster::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
 {
     //prepare shape data
     SwShape* sdata = static_cast<SwShape*>(data);
@@ -39,18 +40,20 @@ void* SwRaster::prepare(const ShapeNode& shape, void* data)
         assert(sdata);
     }
 
+    if (flags == UpdateFlag::None) return nullptr;
+
     //invisible?
     size_t alpha;
     shape.fill(nullptr, nullptr, nullptr, &alpha);
     if (alpha == 0) return sdata;
 
-    if (!shapeGenOutline(shape, *sdata)) return sdata;
-
-    //TODO: From below sequence starts threading?
-    if (!shapeGenRle(shape, *sdata)) return sdata;
-    if (!shapeUpdateBBox(shape, *sdata)) return sdata;
-
-    shapeDelOutline(shape, *sdata);
+    if (flags & UpdateFlag::Path) {
+        if (!shapeGenOutline(shape, *sdata)) return sdata;
+        //TODO: From below sequence starts threading?
+        if (!shapeTransformOutline(shape, *sdata)) return sdata;
+        if (!shapeGenRle(shape, *sdata)) return sdata;
+        shapeDelOutline(shape, *sdata);
+    }
 
     return sdata;
 }
index 07fc274..c690be3 100644 (file)
@@ -20,7 +20,7 @@
 class SwRaster : public RasterMethod
 {
 public:
-    void* prepare(const ShapeNode& shape, void* data) override;
+    void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override;
     static SwRaster* inst();
     static int init();
     static int term();
diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp
new file mode 100644 (file)
index 0000000..d208c53
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *               http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+#ifndef _TVG_SW_RLE_H_
+#define _TVG_SW_RLE_H_
+
+#include <setjmp.h>
+#include "tvgSwCommon.h"
+
+/************************************************************************/
+/* Internal Class Implementation                                        */
+/************************************************************************/
+constexpr auto MAX_SPANS = 256;
+
+using SwPtrDist = ptrdiff_t;
+using TPos = long;
+using TCoord = long;
+using TArea = int;
+
+struct TBand
+{
+    TPos min, max;
+};
+
+struct TCell
+{
+    TPos x;
+    TCoord cover;
+    TArea area;
+    TCell *next;
+};
+
+struct RleWorker
+{
+    TCoord ex, ey;
+    TPos exMin, exMax;
+    TPos eyMin, eyMax;
+    TPos exCnt, eyCnt;
+
+    TArea area;
+    TCoord cover;
+
+    TCell* cells;
+    SwPtrDist maxCells;
+    SwPtrDist numCells;
+
+    TPos x, y;
+
+    Point bezStack[32 * 3 + 1];
+    int   levStack[32];
+
+    SwOutline* outline;
+    //SwBBox clipBox;
+
+    SwSpan spans[MAX_SPANS];
+    int spansCnt;
+
+    //render_span
+    //render_span_data;
+    int ySpan;
+
+    int bandSize;
+    int bandShoot;
+
+    jmp_buf jmpBuf;
+
+    void* buffer;
+    long bufferSize;
+
+    TCell** yCells;
+    TPos   yCnt;
+
+    bool invalid;
+};
+
+static bool rleSweep(RleWorker& rw)
+{
+    //TODO:
+    return true;
+}
+
+static bool moveTo(SwPoint& pt)
+{
+    printf("moveTo = %f %f\n", pt.x, pt.y);
+    return true;
+}
+
+
+static bool lineTo(SwPoint& pt)
+{
+    printf("lineTo = %f %f\n", pt.x, pt.y);
+    return true;
+}
+
+
+static bool cubicTo(SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& pt)
+{
+    printf("cubicTo = ctrl1(%f %f) ctrl2(%f %f) pt(%f %f)\n", ctrl1.x, ctrl1.y, ctrl2.x, ctrl2.y, pt.x, pt.y);
+    return true;
+}
+
+
+static bool decomposeOutline(RleWorker& rw)
+{
+    printf("decomposOutline\n");
+    auto outline = rw.outline;
+    assert(outline);
+
+    auto first = 0;  //index of first point in contour
+
+    for (size_t n = 0; n < outline->cntrsCnt; ++n) {
+        auto last = outline->cntrs[n];
+        if (last < 0) goto invalid_outline;
+
+        auto limit = outline->pts + last;
+        assert(limit);
+
+        auto pt = outline->pts + first;
+        auto tags = outline->tags + first;
+
+        /* A contour cannot start with a cubic control point! */
+        if (tags[0] == SW_CURVE_TAG_CUBIC) goto invalid_outline;
+
+        if (!moveTo(outline->pts[first])) return false;
+
+        while (pt < limit) {
+            assert(++pt);
+            assert(++tags);
+
+            //emit a single line_to
+            if (tags[0] == SW_CURVE_TAG_ON) {
+                if (!lineTo(*pt)) return false;
+                continue;
+            //tag cubic
+            } else {
+                if (pt + 1 > limit || tags[1] != SW_CURVE_TAG_CUBIC)
+                    goto invalid_outline;
+
+                pt += 2;
+                tags += 2;
+
+                if (pt <= limit) {
+                    if (!cubicTo(pt[-2], pt[-1], pt[0])) return false;
+                    continue;
+                }
+                if (!cubicTo(pt[-2], pt[-1], outline->pts[first])) return false;
+                goto close;
+            }
+        }
+
+        //Close the contour with a line segment?
+        //if (!lineTo(outline->pts[first]));
+    close:
+       first = last + 1;
+    }
+
+    return true;
+
+invalid_outline:
+    cout << "Invalid Outline!" << endl;
+    return false;
+}
+
+
+static TCell* findCell(RleWorker& rw)
+{
+    //TODO:
+    return nullptr;
+}
+
+
+static void recordCell(RleWorker& rw)
+{
+    if (rw.area | rw.cover) {
+        TCell* cell = findCell(rw);
+        assert(cell);
+        cell->area += rw.area;
+        cell->cover += rw.cover;
+    }
+}
+
+
+static bool genRle(RleWorker& rw)
+{
+    bool ret = false;
+
+    if (setjmp(rw.jmpBuf) == 0) {
+        ret = decomposeOutline(rw);
+        if (!rw.invalid)  recordCell(rw);
+    } else {
+        cout <<  "Memory Overflow" << endl;
+    }
+    return ret;
+}
+
+
+/************************************************************************/
+/* External Class Implementation                                        */
+/************************************************************************/
+
+bool rleRender(SwShape& sdata)
+{
+    constexpr auto RENDER_POOL_SIZE = 16384L;
+    constexpr auto BAND_SIZE = 40;
+
+    auto outline = sdata.outline;
+    assert(outline);
+
+    if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return false;
+
+    assert(outline->cntrs && outline->pts);
+    assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1);
+
+    //TODO: We can preserve several static workers in advance
+    RleWorker rw;
+    TCell buffer[RENDER_POOL_SIZE / sizeof(TCell)];
+
+    //Init Cells
+    rw.buffer = buffer;
+    rw.bufferSize = sizeof(buffer);
+    rw.yCells = reinterpret_cast<TCell**>(buffer);
+    rw.cells = nullptr;
+    rw.maxCells = 0;
+    rw.numCells = 0;
+    rw.area = 0;
+    rw.cover = 0;
+    rw.invalid = true;
+    rw.exMin = sdata.bbox.xMin;
+    rw.exMax = sdata.bbox.xMax;
+    rw.eyMin = sdata.bbox.yMin;
+    rw.eyMax = sdata.bbox.yMax;
+    rw.exCnt = rw.exMax - rw.exMin;
+    rw.eyCnt = rw.eyMax - rw.eyMin;
+    rw.outline = outline;
+    rw.bandSize = rw.bufferSize / (sizeof(TCell) * 8);  //bandSize: 64
+    rw.bandShoot = 0;
+    //printf("bufferSize = %d, bbox(%d %d %d %d), exCnt(%d), eyCnt(%d), bandSize(%d)\n", rw.bufferSize, rw.exMin, rw.eyMin, rw.exMax, rw.eyMax, rw.exCnt, rw.eyCnt, rw.bandSize);
+
+    //Generate RLE
+    TBand bands[BAND_SIZE];
+    TBand* band;
+
+    /* set up vertical bands */
+    auto bandCnt = (rw.eyMax - rw.eyMin) / rw.bandSize;
+    if (bandCnt == 0) bandCnt = 1;
+    else if (bandCnt >= BAND_SIZE) bandCnt = BAND_SIZE - 1;
+
+    auto min = rw.eyMin;
+    auto yMax = rw.eyMax;
+    TPos max;
+//printf("bandCnt(%d)\n", bandCnt);
+
+    for (int n = 0; n < bandCnt; ++n, min = max) {
+        max = min + rw.bandSize;
+        if (n == bandCnt -1 || max > yMax) max = yMax;
+
+        bands[0].min = min;
+        bands[0].max = max;
+        band = bands;
+
+        while (band >= bands) {
+            rw.yCells = static_cast<TCell**>(rw.buffer);
+            rw.yCnt = band->max - band->min;
+
+            auto cellStart = sizeof(TCell*) * rw.yCnt;
+            auto cellMod = cellStart % sizeof(TCell);
+
+            if (cellMod > 0) cellStart += sizeof(TCell) - cellMod;
+
+            auto cellEnd = rw.bufferSize;
+            cellEnd -= cellEnd % sizeof(TCell);
+//printf("n:%d, cellStart(%d), cellEnd(%d) cellMod(%d)\n", n, cellStart, cellEnd, cellMod);
+
+            auto cellsMax = reinterpret_cast<TCell*>((char*)rw.buffer + cellEnd);
+            rw.cells = reinterpret_cast<TCell*>((char*)rw.buffer + cellStart);
+
+            if (rw.cells >= cellsMax) goto reduce_bands;
+
+            rw.maxCells = cellsMax - rw.cells;
+            if (rw.maxCells < 2) goto reduce_bands;
+
+            for (auto y = 0; y < rw.yCnt; ++y)
+                rw.yCells[y] = nullptr;
+
+            rw.numCells = 0;
+            rw.invalid = true;
+            rw.eyMin = band->min;
+            rw.eyMax = band->max;
+            rw.eyCnt = band->max - band->min;
+
+            if (!genRle(rw)) return -1;
+
+            rleSweep(rw);
+            --band;
+            continue;
+
+        reduce_bands:
+            /* render pool overflow: we will reduce the render band by half */
+            auto bottom = band->min;
+            auto top = band->max;
+            auto middle = bottom + ((top - bottom) >> 1);
+
+            /* This is too complex for a single scanline; there must
+               be some problems */
+            if (middle == bottom) return -1;
+
+            if (bottom - top >= rw.bandSize) ++rw.bandShoot;
+
+            band[1].min = bottom;
+            band[1].max = middle;
+            band[0].min = middle;
+            band[0].max = top;
+            ++band;
+        }
+    }
+
+    if (rw.bandShoot > 8 && rw.bandSize > 16)
+        rw.bandSize = rw.bandSize / 2;
+
+    return true;
+}
+
+#endif /* _TVG_SW_RLE_H_ */
index 364ac3e..746fa89 100644 (file)
@@ -69,7 +69,7 @@ static void outlineEnd(SwOutline& outline)
     growOutlineContour(outline, 1);
     if (outline.ptsCnt > 0) {
         outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
-        ++outline.cntrs;
+        ++outline.cntrsCnt;
     }
 }
 
@@ -150,25 +150,77 @@ static bool outlineClose(SwOutline& outline)
 }
 
 
-/************************************************************************/
-/* External Class Implementation                                        */
-/************************************************************************/
+static void initBBox(SwShape& sdata)
+{
+    sdata.bbox.xMin = sdata.bbox.yMin = 0;
+    sdata.bbox.xMax = sdata.bbox.yMax = 0;
+}
 
-bool shapeGenRle(const ShapeNode& shape, SwShape& sdata)
+
+static bool updateBBox(SwShape& sdata)
 {
-    //TODO: rle
+    auto outline = sdata.outline;
+    assert(outline);
+
+    auto pt = outline->pts;
+    assert(pt);
+
+    if (outline->ptsCnt <= 0) {
+        initBBox(sdata);
+        return false;
+    }
+
+    auto xMin = pt->x;
+    auto xMax = pt->y;
+    auto yMin = pt->y;
+    auto yMax = pt->y;
+
+    ++pt;
+
+    for(size_t i = 1; i < outline->ptsCnt; ++i, ++pt) {
+        assert(pt);
+        if (xMin > pt->x) xMin = pt->x;
+        if (xMax < pt->y) xMax = pt->x;
+        if (yMin > pt->y) yMin = pt->y;
+        if (yMax < pt->y) yMax = pt->y;
+    }
+    sdata.bbox.xMin = round(xMin - 0.49);
+    sdata.bbox.xMax = round(xMax + 0.49);
+    sdata.bbox.yMin = round(yMin - 0.49);
+    sdata.bbox.yMax = round(yMax + 0.49);
+
+    if (xMax - xMin < 1 || yMax - yMin < 1) return false;
 
     return true;
 }
 
 
-bool shapeUpdateBBox(const ShapeNode& shape, SwShape& sdata)
+/************************************************************************/
+/* External Class Implementation                                        */
+/************************************************************************/
+
+bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata)
 {
     //TODO:
     return true;
 }
 
 
+void shapeDelRle(const ShapeNode& shape, SwShape& sdata)
+{
+    if (sdata.rle.spans) free(sdata.rle.spans);
+    sdata.rle.spans = nullptr;
+}
+
+
+bool shapeGenRle(const ShapeNode& shape, SwShape& sdata)
+{
+    shapeDelRle(shape, sdata);
+    if (!updateBBox(sdata)) return false;
+    return rleRender(sdata);
+}
+
+
 void shapeDelOutline(const ShapeNode& shape, SwShape& sdata)
 {
     if (!sdata.outline) return;
@@ -185,6 +237,8 @@ void shapeDelOutline(const ShapeNode& shape, SwShape& sdata)
 
 bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
 {
+    initBBox(sdata);
+
     const PathCommand* cmds = nullptr;
     auto cmdCnt = shape.pathCommands(&cmds);
 
@@ -233,6 +287,7 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
         cout << "Outline was already allocated? How?" << endl;
     }
 
+    //TODO: Probabry we can copy pts from shape directly.
     growOutlinePoint(*outline, outlinePtsCnt);
     growOutlineContour(*outline, outlineCntrsCnt);
 
@@ -264,6 +319,9 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
 
     outlineEnd(*outline);
 
+    //FIXME:
+    //outline->flags = SwOutline::FillRule::Winding;
+
     sdata.outline = outline;
 
     return true;
index dfd908f..e9dc249 100644 (file)
@@ -20,6 +20,7 @@
 #include <iostream>
 #include <cassert>
 #include <vector>
+#include <math.h>
 #include "tizenvg.h"
 
 using namespace std;
@@ -31,8 +32,9 @@ namespace tvg
 class RasterMethod
 {
 public:
+    enum UpdateFlag { None = 0, Path = 1, Fill = 2, All = 3 };
     virtual ~RasterMethod() {}
-    virtual void* prepare(const ShapeNode& shape, void* data) = 0;
+    virtual void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) = 0;
 };
 
 }
index 26735c0..81d97dd 100644 (file)
@@ -89,7 +89,7 @@ int ShapeNode :: update(RasterMethod* engine) noexcept
     auto impl = pImpl.get();
     assert(impl);
 
-    impl->edata = engine->prepare(*this, impl->edata);
+    impl->edata = engine->prepare(*this, impl->edata, RasterMethod::UpdateFlag::All);
     if (impl->edata) return 0;
     return - 1;
 }
@@ -180,9 +180,9 @@ int ShapeNode :: fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept
     assert(impl);
 
     if (r) *r = impl->color[0];
-    if (g) *g = impl->color[0];
-    if (b) *b = impl->color[0];
-    if (a) *a = impl->color[0];
+    if (g) *g = impl->color[1];
+    if (b) *b = impl->color[2];
+    if (a) *a = impl->color[3];
 
     return 0;
 }