newPath = dasher.dashed(mPath);
}
FTOutline *outline = VRaster::toFTOutline(newPath);
- mRle = VRaster::instance().generateStrokeInfo(outline, mStroke.cap, mStroke.join,
- mStroke.width, mStroke.meterLimit);
- VRaster::deleteFTOutline(outline);
+ mRleTask = VRaster::instance().generateStrokeInfo(outline, mStroke.cap, mStroke.join,
+ mStroke.width, mStroke.meterLimit);
} else {
FTOutline *outline = VRaster::toFTOutline(mPath);
- mRle = VRaster::instance().generateFillInfo(outline, mFillRule);
- VRaster::deleteFTOutline(outline);
+ mRleTask = VRaster::instance().generateFillInfo(outline, mFillRule);
}
mFlag &= ~DirtyFlag(DirtyState::Path);
}
}
+VRle VDrawable::rle()
+{
+ if (mRleTask.valid()) {
+ mRle = std::move(mRleTask.get());
+ }
+ return mRle;
+}
+
void VDrawable::setStrokeInfo(CapStyle cap, JoinStyle join, float meterLimit, float strokeWidth)
{
mStroke.enable = true;
}
float opacity = mData->opacity(frameNo);
opacity = opacity * parentAlpha;
+ mCombinedAlpha = opacity;
VPath path = mLocalPath;
path.transform(parentMatrix);
FTOutline *outline = VRaster::toFTOutline(path);
- mRle = VRaster::instance().generateFillInfo(outline);
- VRaster::deleteFTOutline(outline);
-
- mRle = mRle * (opacity * 255);
+ mRleTask = VRaster::instance().generateFillInfo(outline);
+}
- if (mData->mInv) {
- mRle = ~mRle;
+VRle LOTMaskItem::rle()
+{
+ if (mRleTask.valid()) {
+ mRle = std::move(mRleTask.get());
+ if (!vCompare(mCombinedAlpha, 1.0f))
+ mRle = mRle * (mCombinedAlpha * 255);
+ if (mData->mInv)
+ mRle = ~mRle;
}
+ return mRle;
}
void LOTLayerItem::render(VPainter *painter, const VRle &inheritMask)
else
mask = mask & inheritMask;
}
+
+ // do preprocessing first to take advantage of thread pool.
for(auto i : list) {
i->preprocess();
+ }
+
+ for(auto i : list) {
painter->setBrush(i->mBrush);
if (!mask.isEmpty()) {
- VRle rle = i->mRle & mask;
+ VRle rle = i->rle() & mask;
painter->drawRle(VPoint(), rle);
} else {
- painter->drawRle(VPoint(), i->mRle);
+ painter->drawRle(VPoint(), i->rle());
}
}
}
VRle LOTLayerItem::maskRle(const VRect &clipRect)
{
+
VRle rle;
for (auto &i : mMasks) {
switch (i->maskMode()) {
case LOTMaskData::Mode::Add: {
- rle = rle + i->mRle;
+ rle = rle + i->rle();
break;
}
case LOTMaskData::Mode::Substarct: {
if (rle.isEmpty() && !clipRect.isEmpty())
rle = VRle::toRle(clipRect);
- rle = rle - i->mRle;
+ rle = rle - i->rle();
break;
}
case LOTMaskData::Mode::Intersect: {
- rle = rle & i->mRle;
+ rle = rle & i->rle();
break;
}
default:
#include"vmatrix.h"
#include<cstring>
#include"vdebug.h"
+#include"vtaskqueue.h"
+#include<thread>
V_BEGIN_NAMESPACE
bool closed;
};
+
+
#define TO_FT_COORD(x) ((x) * 64) // to freetype 26.6 coordinate.
void FTOutline::transform(const VMatrix &m)
rle->addSpan(rleSpan, count);
}
-VRle generateFillInfoAsync(const SW_FT_Outline *outline)
+struct RleTask
{
- VRle rle;
- SW_FT_Raster_Params params;
+ RleTask() {
+ receiver = sender.get_future();
+ }
+ std::promise<VRle> sender;
+ std::future<VRle> receiver;
+ bool stroke;
+ FTOutline *outline;
+ SW_FT_Stroker_LineCap cap;
+ SW_FT_Stroker_LineJoin join;
+ int width;
+ int meterLimit;
+ SW_FT_Bool closed;
+};
- params.flags = SW_FT_RASTER_FLAG_DIRECT | SW_FT_RASTER_FLAG_AA ;
- params.gray_spans = &rleGenerationCb;
- params.user = &rle;
- params.source = outline;
+static VRle generateRleAsync(RleTask *task);
- sw_ft_grays_raster.raster_render(nullptr, ¶ms);
+class RleTaskScheduler {
+ const unsigned _count{std::thread::hardware_concurrency()};
+ std::vector<std::thread> _threads;
+ std::vector<TaskQueue<RleTask>> _q{_count};
+ std::atomic<unsigned> _index{0};
- return rle;
-}
+ void run(unsigned i) {
+ while (true) {
+ RleTask *task = nullptr;
+
+ for (unsigned n = 0; n != _count * 32; ++n) {
+ if (_q[(i + n) % _count].try_pop(task)) break;
+ }
+ if (!task && !_q[i].pop(task)) break;
+
+ VRle rle = generateRleAsync(task);
+ task->sender.set_value(std::move(rle));
+ delete task;
+ }
+ }
+
+public:
+ RleTaskScheduler() {
+ for (unsigned n = 0; n != _count; ++n) {
+ _threads.emplace_back([&, n] { run(n); });
+ }
+ }
+
+ ~RleTaskScheduler() {
+ for (auto& e : _q)
+ e.done();
+
+ for (auto& e : _threads)
+ e.join();
+ }
+
+ std::future<VRle> async(RleTask *task) {
+ auto receiver = std::move(task->receiver);
+ auto i = _index++;
+
+ for (unsigned n = 0; n != _count; ++n) {
+ if (_q[(i + n) % _count].try_push(task)) return std::move(receiver);
+ }
-VRle generateStrokeInfoAsync(const SW_FT_Outline *outline, SW_FT_Stroker_LineCap cap,
- SW_FT_Stroker_LineJoin join,
- int width, int meterLimit,
- SW_FT_Bool closed)
+ _q[i % _count].push(task);
+
+ return std::move(receiver);
+ }
+
+ std::future<VRle> strokeRle(FTOutline *outline,
+ SW_FT_Stroker_LineCap cap,
+ SW_FT_Stroker_LineJoin join,
+ int width,
+ int meterLimit,
+ SW_FT_Bool closed) {
+ RleTask *task = new RleTask();
+ task->stroke = true;
+ task->outline = outline;
+ task->cap = cap;
+ task->join = join;
+ task->width = width;
+ task->meterLimit = meterLimit;
+ task->closed = closed;
+ return async(task);
+ }
+
+ std::future<VRle> fillRle(FTOutline *outline) {
+ RleTask *task = new RleTask();
+ task->stroke = false;
+ task->outline = outline;
+ return async(task);
+ }
+};
+
+static RleTaskScheduler raster_scheduler;
+
+static VRle generateRleAsync(RleTask *task)
{
- SW_FT_Stroker stroker;
- SW_FT_Stroker_New(&stroker);
+ if (task->stroke) {
+ // for stroke generation
+ SW_FT_Stroker stroker;
+ SW_FT_Stroker_New(&stroker);
- uint points,contors;
- SW_FT_Outline strokeOutline = { 0, 0, nullptr, nullptr, nullptr, SW_FT_OUTLINE_NONE };
+ uint points,contors;
+ SW_FT_Outline strokeOutline = { 0, 0, nullptr, nullptr, nullptr, SW_FT_OUTLINE_NONE };
- SW_FT_Stroker_Set(stroker, width, cap, join, meterLimit);
- SW_FT_Stroker_ParseOutline(stroker, outline, !closed);
- SW_FT_Stroker_GetCounts(stroker,&points, &contors);
+ SW_FT_Stroker_Set(stroker, task->width, task->cap, task->join, task->meterLimit);
+ SW_FT_Stroker_ParseOutline(stroker, &task->outline->ft, !task->closed);
+ SW_FT_Stroker_GetCounts(stroker,&points, &contors);
- strokeOutline.points = (SW_FT_Vector *) calloc(points, sizeof(SW_FT_Vector));
- strokeOutline.tags = (char *) calloc(points, sizeof(char));
- strokeOutline.contours = (short *) calloc(contors, sizeof(short));
+ strokeOutline.points = (SW_FT_Vector *) calloc(points, sizeof(SW_FT_Vector));
+ strokeOutline.tags = (char *) calloc(points, sizeof(char));
+ strokeOutline.contours = (short *) calloc(contors, sizeof(short));
- SW_FT_Stroker_Export(stroker, &strokeOutline);
+ SW_FT_Stroker_Export(stroker, &strokeOutline);
- SW_FT_Stroker_Done(stroker);
+ SW_FT_Stroker_Done(stroker);
- VRle rle = generateFillInfoAsync(&strokeOutline);
+ VRle rle;
+ SW_FT_Raster_Params params;
- // cleanup the outline data.
- free(strokeOutline.points);
- free(strokeOutline.tags);
- free(strokeOutline.contours);
+ params.flags = SW_FT_RASTER_FLAG_DIRECT | SW_FT_RASTER_FLAG_AA ;
+ params.gray_spans = &rleGenerationCb;
+ params.user = &rle;
+ params.source = &strokeOutline;
- return rle;
-}
+ sw_ft_grays_raster.raster_render(nullptr, ¶ms);
+ // cleanup the outline data.
+ free(strokeOutline.points);
+ free(strokeOutline.tags);
+ free(strokeOutline.contours);
+
+ return rle;
+ } else {
+ // fill generation
+ VRle rle;
+ SW_FT_Raster_Params params;
+
+ params.flags = SW_FT_RASTER_FLAG_DIRECT | SW_FT_RASTER_FLAG_AA ;
+ params.gray_spans = &rleGenerationCb;
+ params.user = &rle;
+ params.source = &task->outline->ft;
+
+ sw_ft_grays_raster.raster_render(nullptr, ¶ms);
+
+ return rle;
+ }
+}
VRaster::VRaster()
{
return outline;
}
-VRle VRaster::generateFillInfo(const FTOutline *outline, FillRule fillRule)
+std::future<VRle>
+VRaster::generateFillInfo(FTOutline *outline, FillRule fillRule)
{
int fillRuleFlag = SW_FT_OUTLINE_NONE;
switch (fillRule) {
fillRuleFlag = SW_FT_OUTLINE_NONE;
break;
}
- FTOutline *outlineRef = const_cast<FTOutline *>(outline);
- outlineRef->ft.flags = fillRuleFlag;
- return generateFillInfoAsync(&outlineRef->ft);
+
+ outline->ft.flags = fillRuleFlag;
+
+ return std::move(raster_scheduler.fillRle(outline));
}
-VRle VRaster::generateStrokeInfo(const FTOutline *outline, CapStyle cap, JoinStyle join,
- float width, float meterLimit)
+std::future<VRle>
+VRaster::generateStrokeInfo(FTOutline *outline, CapStyle cap, JoinStyle join,
+ float width, float meterLimit)
{
SW_FT_Stroker_LineCap ftCap;
SW_FT_Stroker_LineJoin ftJoin;
int ftWidth;
int ftMeterLimit;
- SW_FT_Bool ftbool = (SW_FT_Bool) outline->closed;
+ SW_FT_Bool ftclose = (SW_FT_Bool) outline->closed;
// map strokeWidth to freetype. It uses as the radius of the pen not the diameter
width = width/2.0;
break;
}
- return generateStrokeInfoAsync(&outline->ft, ftCap, ftJoin,
- ftWidth, ftMeterLimit, ftbool);
+ return std::move(raster_scheduler.strokeRle(outline, ftCap, ftJoin,
+ ftWidth, ftMeterLimit, ftclose));
}
V_END_NAMESPACE