virtual Result update() noexcept;
virtual Result update(Paint* paint) noexcept;
virtual Result draw(bool async = true) noexcept;
- virtual Result sync() = 0;
+ virtual Result sync() noexcept;
_TVG_DECLARE_ACCESSOR(Scene);
_TVG_DECLARE_PRIVATE(Canvas);
~SwCanvas();
Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept;
- Result sync() noexcept override;
static std::unique_ptr<SwCanvas> gen() noexcept;
~GlCanvas();
//TODO: Gl Specific methods. Need gl backend configuration methods as well.
-
Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept;
- Result sync() noexcept override;
static std::unique_ptr<GlCanvas> gen() noexcept;
}
-void GlRenderer::flush()
+bool GlRenderer::flush()
{
GL_CHECK(glFinish());
mColorProgram->unload();
+
+ return true;
+}
+
+
+bool GlRenderer::preRender()
+{
+ //TODO: called just before render()
+
+ return true;
+}
+
+
+bool GlRenderer::postRender()
+{
+ //TODO: called just after render()
+
+ return true;
}
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override;
bool dispose(const Shape& shape, void *data) override;
+ bool preRender() override;
bool render(const Shape& shape, void *data) override;
+ bool postRender() override;
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h);
- void flush();
+ bool flush() override;
bool clear() override;
uint32_t ref() override;
uint32_t unref() override;
#ifndef _TVG_SW_COMMON_H_
#define _TVG_SW_COMMON_H_
-#include <future>
-#include <thread>
#include "tvgCommon.h"
#if 0
};
-struct SwTask
-{
- SwShape shape;
- const Shape* sdata;
- SwSize clip;
- const Matrix* transform;
- RenderUpdateFlag flags;
- future<void> prepared;
-};
-
static inline SwPoint TO_SWPOINT(const Point* pt)
{
return {SwCoord(pt->x * 64), SwCoord(pt->y * 64)};
#ifndef _TVG_SW_RENDERER_CPP_
#define _TVG_SW_RENDERER_CPP_
+using namespace std;
+
#include "tvgSwCommon.h"
#include "tvgSwRenderer.h"
/************************************************************************/
/* Internal Class Implementation */
/************************************************************************/
+namespace tvg {
+ struct SwTask
+ {
+ SwShape shape;
+ const Shape* sdata;
+ SwSize clip;
+ const Matrix* transform;
+ RenderUpdateFlag flags;
+ future<void> progress;
+ };
+}
static RenderInitializer renderInit;
+
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
-bool SwRenderer::clear()
+SwRenderer::~SwRenderer()
{
- return rasterClear(surface);
+ if (progress.valid()) progress.get();
}
+bool SwRenderer::clear()
+{
+ if (progress.valid()) return false;
+ return true;
+}
+
bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h)
{
if (!buffer || stride == 0 || w == 0 || h == 0) return false;
}
-bool SwRenderer::render(const Shape& sdata, void *data)
+bool SwRenderer::preRender()
{
- auto task = static_cast<SwTask*>(data);
- if (!task) return false;
+ //before we start rendering, we should finish all preparing tasks
+ while (prepareTasks.size() > 0) {
+ auto task = prepareTasks.front();
+ if (task->progress.valid()) task->progress.get();
+ prepareTasks.pop();
+ renderTasks.push(task);
+ }
+ return true;
+}
- if (task->prepared.valid()) task->prepared.get();
- uint8_t r, g, b, a;
+bool SwRenderer::postRender()
+{
+ auto asyncTask = [](SwRenderer* renderer) {
+ renderer->doRender();
+ };
- if (auto fill = sdata.fill()) {
- rasterGradientShape(surface, task->shape, fill->id());
- } else {
- sdata.fill(&r, &g, &b, &a);
- if (a > 0) rasterSolidShape(surface, task->shape, r, g, b, a);
+ progress = async(launch::async, asyncTask, this);
+
+ return true;
+}
+
+
+void SwRenderer::doRender()
+{
+ rasterClear(surface);
+
+ while (renderTasks.size() > 0) {
+ auto task = renderTasks.front();
+ uint8_t r, g, b, a;
+ if (auto fill = task->sdata->fill()) {
+ rasterGradientShape(surface, task->shape, fill->id());
+ } else{
+ task->sdata->fill(&r, &g, &b, &a);
+ if (a > 0) rasterSolidShape(surface, task->shape, r, g, b, a);
+ }
+ task->sdata->strokeColor(&r, &g, &b, &a);
+ if (a > 0) rasterStroke(surface, task->shape, r, g, b, a);
+ renderTasks.pop();
+ }
+}
+
+
+bool SwRenderer::flush()
+{
+ if (progress.valid()) {
+ progress.get();
+ return true;
}
+ return false;
+}
+
- sdata.strokeColor(&r, &g, &b, &a);
- if (a > 0) rasterStroke(surface, task->shape, r, g, b, a);
+bool SwRenderer::render(const Shape& sdata, void *data)
+{
+ //Do Nothing
return true;
}
{
auto task = static_cast<SwTask*>(data);
if (!task) return true;
- if (task->prepared.valid()) task->prepared.wait();
+ if (task->progress.valid()) task->progress.get();
shapeFree(task->shape);
free(task);
return true;
if (!task) return nullptr;
}
- if (flags == RenderUpdateFlag::None || task->prepared.valid()) return task;
+ if (flags == RenderUpdateFlag::None || task->progress.valid()) return task;
task->sdata = &sdata;
task->clip = {static_cast<SwCoord>(surface.w), static_cast<SwCoord>(surface.h)};
shapeDelOutline(task->shape);
};
- task->prepared = async((launch::async | launch::deferred), asyncTask, task);
+ prepareTasks.push(task);
+ task->progress = async((launch::async | launch::deferred), asyncTask, task);
return task;
}
#ifndef _TVG_SW_RENDERER_H_
#define _TVG_SW_RENDERER_H_
+#include <queue>
+#include <future>
+#include <thread>
+
+namespace tvg
+{
+
+struct SwTask;
+
class SwRenderer : public RenderMethod
{
public:
- Surface surface;
-
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override;
bool dispose(const Shape& shape, void *data) override;
+ bool preRender() override;
bool render(const Shape& shape, void *data) override;
+ bool postRender() override;
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h);
bool clear() override;
+ bool flush() override;
uint32_t ref() override;
uint32_t unref() override;
static int init();
static int term();
+ void doRender(); //Internally used for threading
+
private:
+ Surface surface;
+ future<void> progress;
+ queue<SwTask*> prepareTasks;
+ queue<SwTask*> renderTasks;
+
SwRenderer(){};
- ~SwRenderer(){};
+ ~SwRenderer();
};
+}
+
#endif /* _TVG_SW_RENDERER_H_ */
shapeDelOutline(shape);
rleFree(shape.rle);
+ shapeDelFill(shape);
+
if (shape.stroke) {
rleFree(shape.strokeRle);
strokeFree(shape.stroke);
return impl->update(paint);
}
+
+Result Canvas::sync() noexcept
+{
+ auto impl = pImpl.get();
+ if (!impl) return Result::MemoryCorruption;
+
+ if (impl->renderer->flush()) return Result::Success;
+
+ return Result::InsufficientCondition;
+}
+
#endif /* _TVG_CANVAS_CPP_ */
{
if (!renderer) return Result::InsufficientCondition;
+ //Clear render target before drawing
+ if (!renderer->clear()) return Result::InsufficientCondition;
+
for (auto paint : paints) {
if (paint->id() == PAINT_ID_SCENE) {
//We know renderer type, avoid dynamic_cast for performance.
{
if (!renderer) return Result::InsufficientCondition;
- //Clear render target before drawing
- if (!renderer->clear()) return Result::InsufficientCondition;
+ if (!renderer->preRender()) return Result::InsufficientCondition;
for(auto paint: paints) {
if (paint->id() == PAINT_ID_SCENE) {
if(!SHAPE_IMPL->render(*shape, *renderer)) return Result::InsufficientCondition;
}
}
+
+ if (!renderer->postRender()) return Result::InsufficientCondition;
+
return Result::Success;
}
};
}
-Result GlCanvas::sync() noexcept
-{
- auto renderer = dynamic_cast<GlRenderer*>(Canvas::pImpl.get()->renderer);
- assert(renderer);
-
- renderer->flush();
- return Result::Success;
-}
-
-
unique_ptr<GlCanvas> GlCanvas::gen() noexcept
{
auto canvas = unique_ptr<GlCanvas>(new GlCanvas);
virtual ~RenderMethod() {}
virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) = 0;
virtual bool dispose(const Shape& shape, void *data) = 0;
+ virtual bool preRender() = 0;
virtual bool render(const Shape& shape, void *data) = 0;
+ virtual bool postRender() = 0;
virtual bool clear() = 0;
+ virtual bool flush() = 0;
virtual uint32_t ref() = 0;
virtual uint32_t unref() = 0;
};
{
}
+
Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept
{
//We know renderer type, avoid dynamic_cast for performance.
}
-Result SwCanvas::sync() noexcept
-{
- return Result::Success;
-}
-
-
unique_ptr<SwCanvas> SwCanvas::gen() noexcept
{
auto canvas = unique_ptr<SwCanvas>(new SwCanvas);
Eina_Bool anim_cb(void *data)
{
+ auto t = ecore_time_get();
+
//Explicitly clear all retained paint nodes.
- t1 = ecore_time_get();
- canvas->clear();
+ if (canvas->clear() != tvg::Result::Success)
+ {
+ //Probably, you missed sync() call before.
+ return ECORE_CALLBACK_RENEW;
+ }
+
+ t1 = t;
+
t2 = ecore_time_get();
for (int i = 0; i < COUNT; i++) {
canvas->push(move(shape));
}
+ t3 = ecore_time_get();
+
+ //Draw Next frames
+ canvas->draw();
+
//Update Efl Canvas
Eo* img = (Eo*) data;
evas_object_image_pixels_dirty_set(img, EINA_TRUE);
void render_cb(void* data, Eo* obj)
{
- t3 = ecore_time_get();
-
- //Draw Next frames
- canvas->draw();
canvas->sync();
t4 = ecore_time_get();