ThorVG: update from v0.12.1 to v0.12.3

https://github.com/thorvg/thorvg/releases/tag/v0.12.3

+ Full Changelog:
  https://github.com/thorvg/thorvg/compare/v0.12.1...v0.12.3

Godot-related SVG bug fixes:

+ svg_loader: Add missing transform functions skewX and skewY.
  thorvg/thorvg#1928
+ sw_engine: Rectified dash line drawing issue.
  thorvg/thorvg#1932
This commit is contained in:
Martin Capitanio 2024-01-26 10:04:27 +01:00
parent 99ac3d332a
commit 73589f6db6
14 changed files with 209 additions and 142 deletions

View file

@ -859,7 +859,7 @@ instead of `miniz.h` as an external dependency.
## thorvg
- Upstream: https://github.com/thorvg/thorvg
- Version: 0.12.1 (d761e3c5622c0ffba2e5bb40da05751e2451e495, 2024)
- Version: 0.12.3 (9d79f0ccef632fd3b43b8ea02def529b6a8d2288, 2024)
- License: MIT
Files extracted from upstream source:

View file

@ -9,5 +9,5 @@
// For internal debugging:
//#define THORVG_LOG_ENABLED
#define THORVG_VERSION_STRING "0.12.1"
#define THORVG_VERSION_STRING "0.12.3"
#endif

70
thirdparty/thorvg/src/common/tvgLock.h vendored Normal file
View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _TVG_LOCK_H_
#define _TVG_LOCK_H_
#ifdef THORVG_THREAD_SUPPORT
#include <mutex>
namespace tvg {
struct Key
{
std::mutex mtx;
};
struct ScopedLock
{
Key* key = nullptr;
ScopedLock(Key& key)
{
key.mtx.lock();
this->key = &key;
}
~ScopedLock()
{
key->mtx.unlock();
}
};
}
#else //THORVG_THREAD_SUPPORT
namespace tvg {
struct Key {};
struct ScopedLock
{
ScopedLock(Key& key) {}
};
}
#endif //THORVG_THREAD_SUPPORT
#endif //_TVG_LOCK_H_

View file

@ -683,32 +683,6 @@ static constexpr struct
};
static void _matrixCompose(const Matrix* m1, const Matrix* m2, Matrix* dst)
{
auto a11 = (m1->e11 * m2->e11) + (m1->e12 * m2->e21) + (m1->e13 * m2->e31);
auto a12 = (m1->e11 * m2->e12) + (m1->e12 * m2->e22) + (m1->e13 * m2->e32);
auto a13 = (m1->e11 * m2->e13) + (m1->e12 * m2->e23) + (m1->e13 * m2->e33);
auto a21 = (m1->e21 * m2->e11) + (m1->e22 * m2->e21) + (m1->e23 * m2->e31);
auto a22 = (m1->e21 * m2->e12) + (m1->e22 * m2->e22) + (m1->e23 * m2->e32);
auto a23 = (m1->e21 * m2->e13) + (m1->e22 * m2->e23) + (m1->e23 * m2->e33);
auto a31 = (m1->e31 * m2->e11) + (m1->e32 * m2->e21) + (m1->e33 * m2->e31);
auto a32 = (m1->e31 * m2->e12) + (m1->e32 * m2->e22) + (m1->e33 * m2->e32);
auto a33 = (m1->e31 * m2->e13) + (m1->e32 * m2->e23) + (m1->e33 * m2->e33);
dst->e11 = a11;
dst->e12 = a12;
dst->e13 = a13;
dst->e21 = a21;
dst->e22 = a22;
dst->e23 = a23;
dst->e31 = a31;
dst->e32 = a32;
dst->e33 = a33;
}
/* parse transform attribute
* https://www.w3.org/TR/SVG/coords.html#TransformAttribute
*/
@ -751,14 +725,14 @@ static Matrix* _parseTransformationMatrix(const char* value)
if (state == MatrixState::Matrix) {
if (ptCount != 6) goto error;
Matrix tmp = {points[0], points[2], points[4], points[1], points[3], points[5], 0, 0, 1};
_matrixCompose(matrix, &tmp, matrix);
*matrix = mathMultiply(matrix, &tmp);
} else if (state == MatrixState::Translate) {
if (ptCount == 1) {
Matrix tmp = {1, 0, points[0], 0, 1, 0, 0, 0, 1};
_matrixCompose(matrix, &tmp, matrix);
*matrix = mathMultiply(matrix, &tmp);
} else if (ptCount == 2) {
Matrix tmp = {1, 0, points[0], 0, 1, points[1], 0, 0, 1};
_matrixCompose(matrix, &tmp, matrix);
*matrix = mathMultiply(matrix, &tmp);
} else goto error;
} else if (state == MatrixState::Rotate) {
//Transform to signed.
@ -768,14 +742,14 @@ static Matrix* _parseTransformationMatrix(const char* value)
auto s = sinf(points[0] * (M_PI / 180.0));
if (ptCount == 1) {
Matrix tmp = { c, -s, 0, s, c, 0, 0, 0, 1 };
_matrixCompose(matrix, &tmp, matrix);
*matrix = mathMultiply(matrix, &tmp);
} else if (ptCount == 3) {
Matrix tmp = { 1, 0, points[1], 0, 1, points[2], 0, 0, 1 };
_matrixCompose(matrix, &tmp, matrix);
*matrix = mathMultiply(matrix, &tmp);
tmp = { c, -s, 0, s, c, 0, 0, 0, 1 };
_matrixCompose(matrix, &tmp, matrix);
*matrix = mathMultiply(matrix, &tmp);
tmp = { 1, 0, -points[1], 0, 1, -points[2], 0, 0, 1 };
_matrixCompose(matrix, &tmp, matrix);
*matrix = mathMultiply(matrix, &tmp);
} else {
goto error;
}
@ -785,7 +759,17 @@ static Matrix* _parseTransformationMatrix(const char* value)
auto sy = sx;
if (ptCount == 2) sy = points[1];
Matrix tmp = { sx, 0, 0, 0, sy, 0, 0, 0, 1 };
_matrixCompose(matrix, &tmp, matrix);
*matrix = mathMultiply(matrix, &tmp);
} else if (state == MatrixState::SkewX) {
if (ptCount != 1) goto error;
auto deg = tanf(points[0] * (M_PI / 180.0));
Matrix tmp = { 1, deg, 0, 0, 1, 0, 0, 0, 1 };
*matrix = mathMultiply(matrix, &tmp);
} else if (state == MatrixState::SkewY) {
if (ptCount != 1) goto error;
auto deg = tanf(points[0] * (M_PI / 180.0));
Matrix tmp = { 1, 0, 0, deg, 1, 0, 0, 0, 1 };
*matrix = mathMultiply(matrix, &tmp);
}
}
return matrix;

View file

@ -257,8 +257,8 @@ static uint32_t _interpUpScaler(const uint32_t *img, TVG_UNUSED uint32_t stride,
auto ry2 = ry + 1;
if (ry2 >= h) ry2 = h - 1;
auto dx = static_cast<size_t>((sx - rx) * 255.0f);
auto dy = static_cast<size_t>((sy - ry) * 255.0f);
auto dx = static_cast<uint8_t>((sx - rx) * 255.0f);
auto dy = static_cast<uint8_t>((sy - ry) * 255.0f);
auto c1 = img[rx + ry * w];
auto c2 = img[rx2 + ry * w];
@ -281,21 +281,23 @@ static uint32_t _interpDownScaler(const uint32_t *img, uint32_t stride, uint32_t
int32_t maxx = (int32_t)sx + n;
if (maxx >= (int32_t)w) maxx = w;
int32_t inc = (n / 2) + 1;
n = 0;
auto src = img + minx + miny * stride;
for (auto y = miny; y < maxy; ++y) {
for (auto y = miny; y < maxy; y += inc) {
auto p = src;
for (auto x = minx; x < maxx; ++x, ++p) {
c[0] += *p >> 24;
c[1] += (*p >> 16) & 0xff;
c[2] += (*p >> 8) & 0xff;
c[3] += *p & 0xff;
for (auto x = minx; x < maxx; x += inc, p += inc) {
c[0] += A(*p);
c[1] += C1(*p);
c[2] += C2(*p);
c[3] += C3(*p);
++n;
}
src += stride;
src += (stride * inc);
}
n = (maxy - miny) * (maxx - minx);
c[0] /= n;
c[1] /= n;
c[2] /= n;
@ -1855,7 +1857,7 @@ void rasterUnpremultiply(Surface* surface)
void rasterPremultiply(Surface* surface)
{
unique_lock<mutex> lock{surface->mtx};
ScopedLock lock(surface->key);
if (surface->premultiplied || (surface->channelSize != sizeof(uint32_t))) return;
surface->premultiplied = true;
@ -1936,7 +1938,7 @@ bool rasterImage(SwSurface* surface, SwImage* image, const RenderMesh* mesh, con
bool rasterConvertCS(Surface* surface, ColorSpace to)
{
unique_lock<mutex> lock{surface->mtx};
ScopedLock lock(surface->key);
if (surface->cs == to) return true;
//TOOD: Support SIMD accelerations

View file

@ -528,8 +528,8 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image,
vv = (int) v;
if (vv >= sh) continue;
ar = (int)(255 * (1 - modff(u, &iptr)));
ab = (int)(255 * (1 - modff(v, &iptr)));
ar = (int)(255.0f * (1.0f - modff(u, &iptr)));
ab = (int)(255.0f * (1.0f - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
@ -576,8 +576,8 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image,
uu = (int) u;
vv = (int) v;
ar = (int)(255 * (1 - modff(u, &iptr)));
ab = (int)(255 * (1 - modff(v, &iptr)));
ar = (int)(255.0f * (1.0f - modff(u, &iptr)));
ab = (int)(255.0f * (1.0f - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;

View file

@ -425,6 +425,8 @@ bool SwRenderer::target(pixel_t* data, uint32_t stride, uint32_t w, uint32_t h,
{
if (!data || stride == 0 || w == 0 || h == 0 || w > stride) return false;
clearCompositors();
if (!surface) surface = new SwSurface;
surface->data = data;
@ -474,7 +476,6 @@ bool SwRenderer::postRender()
}
tasks.clear();
clearCompositors();
return true;
}

View file

@ -64,12 +64,16 @@ static void _outlineEnd(SwOutline& outline)
{
if (outline.pts.empty()) return;
outline.cntrs.push(outline.pts.count - 1);
outline.closed.push(false);
}
static void _outlineMoveTo(SwOutline& outline, const Point* to, const Matrix* transform)
{
if (outline.pts.count > 0) outline.cntrs.push(outline.pts.count - 1);
if (outline.pts.count > 0) {
outline.cntrs.push(outline.pts.count - 1);
outline.closed.push(false);
}
outline.pts.push(mathTransform(to, transform));
outline.types.push(SW_CURVE_TYPE_POINT);
@ -128,7 +132,7 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to, const Matrix* trans
_outlineLineTo(*dash.outline, to, transform);
}
} else {
while (len > dash.curLen) {
while (len - dash.curLen > 0.0001f) {
Line left, right;
if (dash.curLen > 0) {
len -= dash.curLen;
@ -185,7 +189,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct
_outlineCubicTo(*dash.outline, ctrl1, ctrl2, to, transform);
}
} else {
while (len > dash.curLen) {
while ((len - dash.curLen) > 0.0001f) {
Bezier left, right;
if (dash.curLen > 0) {
len -= dash.curLen;
@ -315,21 +319,6 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
dash.outline = mpoolReqDashOutline(mpool, tid);
//smart reservation
auto closeCnt = 0;
auto moveCnt = 0;
for (auto cmd = rshape->path.cmds.data; cmd < rshape->path.cmds.end(); ++cmd) {
if (*cmd == PathCommand::Close) ++closeCnt;
else if (*cmd == PathCommand::MoveTo) ++moveCnt;
}
//No idea exact count.... Reserve Approximitely 20x...
//OPTIMIZE: we can directly copy the path points when the close is occupied with a point.
dash.outline->pts.grow(20 * (closeCnt + ptsCnt + 1));
dash.outline->types.grow(20 * (closeCnt + ptsCnt + 1));
dash.outline->cntrs.grow(20 * (moveCnt + 1));
while (cmdCnt-- > 0) {
switch (*cmds) {
case PathCommand::Close: {
@ -435,29 +424,9 @@ static bool _genOutline(SwShape* shape, const RenderShape* rshape, const Matrix*
//No actual shape data
if (cmdCnt == 0 || ptsCnt == 0) return false;
//smart reservation
auto moveCnt = 0;
auto closeCnt = 0;
for (auto cmd = rshape->path.cmds.data; cmd < rshape->path.cmds.end(); ++cmd) {
if (*cmd == PathCommand::Close) ++closeCnt;
else if (*cmd == PathCommand::MoveTo) ++moveCnt;
}
shape->outline = mpoolReqOutline(mpool, tid);
auto outline = shape->outline;
//OPTIMIZE: we can directly copy the path points when the close is occupied with a point.
outline->pts.grow(ptsCnt + closeCnt + 1);
outline->types.grow(ptsCnt + closeCnt + 1);
outline->cntrs.grow(moveCnt + 1);
//Dash outlines are always opened.
//Only normal outlines use this information, it sholud be same to their contour counts.
outline->closed.reserve(outline->cntrs.reserved);
memset(outline->closed.data, 0x0, sizeof(bool) * outline->closed.reserved);
//Generate Outlines
while (cmdCnt-- > 0) {
switch (*cmds) {

View file

@ -24,6 +24,7 @@
#include "tvgInlist.h"
#include "tvgLoader.h"
#include "tvgLock.h"
#ifdef THORVG_SVG_LOADER_SUPPORT
#include "tvgSvgLoader.h"
@ -65,7 +66,7 @@ uint64_t HASH_KEY(const char* data, uint64_t size)
/* Internal Class Implementation */
/************************************************************************/
static mutex mtx;
static Key key;
static Inlist<LoadModule> _activeLoaders;
@ -211,7 +212,7 @@ static LoadModule* _findByType(const string& mimeType)
static LoadModule* _findFromCache(const string& path)
{
unique_lock<mutex> lock{mtx};
ScopedLock lock(key);
auto loader = _activeLoaders.head;
@ -231,7 +232,7 @@ static LoadModule* _findFromCache(const char* data, uint32_t size, const string&
auto type = _convert(mimeType);
if (type == FileType::Unknown) return nullptr;
unique_lock<mutex> lock{mtx};
ScopedLock lock(key);
auto loader = _activeLoaders.head;
auto key = HASH_KEY(data, size);
@ -279,7 +280,7 @@ bool LoaderMgr::retrieve(LoadModule* loader)
if (!loader) return false;
if (loader->close()) {
{
unique_lock<mutex> lock{mtx};
ScopedLock lock(key);
_activeLoaders.remove(loader);
}
delete(loader);
@ -298,7 +299,7 @@ LoadModule* LoaderMgr::loader(const string& path, bool* invalid)
if (loader->open(path)) {
loader->hashpath = strdup(path.c_str());
{
unique_lock<mutex> lock{mtx};
ScopedLock lock(key);
_activeLoaders.back(loader);
}
return loader;
@ -340,7 +341,7 @@ LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const string& mim
if (auto loader = _findByType(mimeType)) {
if (loader->open(data, size, copy)) {
loader->hashkey = HASH_KEY(data, size);
unique_lock<mutex> lock{mtx};
ScopedLock lock(key);
_activeLoaders.back(loader);
return loader;
} else {
@ -356,7 +357,7 @@ LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const string& mim
if (loader->open(data, size, copy)) {
loader->hashkey = HASH_KEY(data, size);
{
unique_lock<mutex> lock{mtx};
ScopedLock lock(key);
_activeLoaders.back(loader);
}
return loader;
@ -379,7 +380,7 @@ LoadModule* LoaderMgr::loader(const uint32_t *data, uint32_t w, uint32_t h, bool
if (loader->open(data, w, h, copy)) {
loader->hashkey = HASH_KEY((const char*)data, w * h);
{
unique_lock<mutex> lock{mtx};
ScopedLock lock(key);
_activeLoaders.back(loader);
}
return loader;

View file

@ -23,9 +23,9 @@
#ifndef _TVG_RENDER_H_
#define _TVG_RENDER_H_
#include <mutex>
#include "tvgCommon.h"
#include "tvgArray.h"
#include "tvgLock.h"
namespace tvg
{
@ -54,7 +54,7 @@ struct Surface
uint32_t* buf32; //for explicit 32bits channels
uint8_t* buf8; //for explicit 8bits grayscale
};
mutex mtx; //used for thread safety
Key key; //a reserved lock for the thread safety
uint32_t stride = 0;
uint32_t w = 0, h = 0;
ColorSpace cs = ColorSpace::Unsupported;

View file

@ -130,11 +130,11 @@ Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept
auto ryKappa = ry * PATH_KAPPA;
pImpl->grow(6, 13);
pImpl->moveTo(cx + rx, cy);
pImpl->moveTo(cx, cy - ry);
pImpl->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy);
pImpl->cubicTo(cx + rx, cy + ryKappa, cx + rxKappa, cy + ry, cx, cy + ry);
pImpl->cubicTo(cx - rxKappa, cy + ry, cx - rx, cy + ryKappa, cx - rx, cy);
pImpl->cubicTo(cx - rx, cy - ryKappa, cx - rxKappa, cy - ry, cx, cy - ry);
pImpl->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy);
pImpl->close();
return Result::Success;
@ -216,21 +216,19 @@ Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry)
pImpl->lineTo(x, y + h);
pImpl->close();
//circle
} else if (mathEqual(rx, halfW) && mathEqual(ry, halfH)) {
return appendCircle(x + (w * 0.5f), y + (h * 0.5f), rx, ry);
} else {
auto hrx = rx * PATH_KAPPA;
auto hry = ry * PATH_KAPPA;
pImpl->grow(10, 17);
pImpl->moveTo(x + rx, y);
pImpl->lineTo(x + w - rx, y);
pImpl->cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry);
pImpl->moveTo(x + w, y + ry);
pImpl->lineTo(x + w, y + h - ry);
pImpl->cubicTo(x + w, y + h - ry + hry, x + w - rx + hrx, y + h, x + w - rx, y + h);
pImpl->lineTo(x + rx, y + h);
pImpl->cubicTo(x + rx - hrx, y + h, x, y + h - ry + hry, x, y + h - ry);
pImpl->lineTo(x, y + ry);
pImpl->cubicTo(x, y + ry - hry, x + rx - hrx, y, x + rx, y);
pImpl->lineTo(x + w - rx, y);
pImpl->cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry);
pImpl->close();
}

View file

@ -20,19 +20,28 @@
* SOFTWARE.
*/
#include <thread>
#include <atomic>
#include <condition_variable>
#include "tvgArray.h"
#include "tvgInlist.h"
#include "tvgTaskScheduler.h"
#ifdef THORVG_THREAD_SUPPORT
#include <thread>
#include <atomic>
#endif
/************************************************************************/
/* Internal Class Implementation */
/************************************************************************/
namespace tvg {
struct TaskSchedulerImpl;
static TaskSchedulerImpl* inst = nullptr;
#ifdef THORVG_THREAD_SUPPORT
static thread_local bool _async = true;
struct TaskQueue {
Inlist<Task> taskDeque;
mutex mtx;
@ -61,7 +70,7 @@ struct TaskQueue {
void complete()
{
{
unique_lock<mutex> lock{mtx};
lock_guard<mutex> lock{mtx};
done = true;
}
ready.notify_all();
@ -84,7 +93,7 @@ struct TaskQueue {
void push(Task* task)
{
{
unique_lock<mutex> lock{mtx};
lock_guard<mutex> lock{mtx};
taskDeque.back(task);
}
ready.notify_one();
@ -92,25 +101,22 @@ struct TaskQueue {
};
static thread_local bool _async = true; //toggle async tasking for each thread on/off
struct TaskSchedulerImpl
{
Array<thread*> threads;
Array<TaskQueue*> taskQueues;
atomic<uint32_t> idx{0};
TaskSchedulerImpl(unsigned threadCnt)
TaskSchedulerImpl(uint32_t threadCnt)
{
threads.reserve(threadCnt);
taskQueues.reserve(threadCnt);
for (unsigned i = 0; i < threadCnt; ++i) {
for (uint32_t i = 0; i < threadCnt; ++i) {
taskQueues.push(new TaskQueue);
threads.push(new thread);
}
for (unsigned i = 0; i < threadCnt; ++i) {
for (uint32_t i = 0; i < threadCnt; ++i) {
*threads.data[i] = thread([&, i] { run(i); });
}
}
@ -136,7 +142,7 @@ struct TaskSchedulerImpl
//Thread Loop
while (true) {
auto success = false;
for (unsigned x = 0; x < threads.count * 2; ++x) {
for (uint32_t x = 0; x < threads.count * 2; ++x) {
if (taskQueues[(i + x) % threads.count]->tryPop(&task)) {
success = true;
break;
@ -154,7 +160,7 @@ struct TaskSchedulerImpl
if (threads.count > 0 && _async) {
task->prepare();
auto i = idx++;
for (unsigned n = 0; n < threads.count; ++n) {
for (uint32_t n = 0; n < threads.count; ++n) {
if (taskQueues[(i + n) % threads.count]->tryPush(task)) return;
}
taskQueues[i % threads.count]->push(task);
@ -163,17 +169,33 @@ struct TaskSchedulerImpl
task->run(0);
}
}
uint32_t threadCnt()
{
return threads.count;
}
};
}
#else //THORVG_THREAD_SUPPORT
static TaskSchedulerImpl* inst = nullptr;
static bool _async = true;
struct TaskSchedulerImpl
{
TaskSchedulerImpl(TVG_UNUSED uint32_t threadCnt) {}
void request(Task* task) { task->run(0); }
uint32_t threadCnt() { return 0; }
};
#endif //THORVG_THREAD_SUPPORT
} //namespace
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
void TaskScheduler::init(unsigned threads)
void TaskScheduler::init(uint32_t threads)
{
if (inst) return;
inst = new TaskSchedulerImpl(threads);
@ -182,7 +204,6 @@ void TaskScheduler::init(unsigned threads)
void TaskScheduler::term()
{
if (!inst) return;
delete(inst);
inst = nullptr;
}
@ -194,14 +215,15 @@ void TaskScheduler::request(Task* task)
}
unsigned TaskScheduler::threads()
uint32_t TaskScheduler::threads()
{
if (inst) return inst->threads.count;
if (inst) return inst->threadCnt();
return 0;
}
void TaskScheduler::async(bool on)
{
//toggle async tasking for each thread on/off
_async = on;
}

View file

@ -25,22 +25,13 @@
#include <mutex>
#include <condition_variable>
#include "tvgCommon.h"
#include "tvgInlist.h"
namespace tvg
{
namespace tvg {
struct Task;
struct TaskScheduler
{
static unsigned threads();
static void init(unsigned threads);
static void term();
static void request(Task* task);
static void async(bool on);
};
#ifdef THORVG_THREAD_SUPPORT
struct Task
{
@ -86,7 +77,36 @@ private:
friend struct TaskSchedulerImpl;
};
}
#else //THORVG_THREAD_SUPPORT
struct Task
{
public:
INLIST_ITEM(Task);
virtual ~Task() = default;
void done() {}
protected:
virtual void run(unsigned tid) = 0;
private:
friend struct TaskSchedulerImpl;
};
#endif //THORVG_THREAD_SUPPORT
struct TaskScheduler
{
static uint32_t threads();
static void init(uint32_t threads);
static void term();
static void request(Task* task);
static void async(bool on);
};
} //namespace
#endif //_TVG_TASK_SCHEDULER_H_

View file

@ -1,6 +1,6 @@
#!/bin/bash -e
VERSION=0.12.1
VERSION=0.12.3
cd thirdparty/thorvg/ || true
rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/