blob: 1fbbec6ee79df4c0d0e7b89ebd4da9d51122af8b [file] [log] [blame] [edit]
/*
* Copyright 2022 Rive
*/
#include "bench.hpp"
#include "common/render_context_null.hpp"
#include "rive/file.hpp"
#include "rive/scene.hpp"
#include "assets/paper.riv.hpp"
#include "rive/renderer/rive_renderer.hpp"
#include "rive/renderer/render_context.hpp"
#include "rive_render_paint.hpp"
#include "rive_render_path.hpp"
using namespace rive;
using namespace rive::gpu;
using PathPaint = std::tuple<rcp<RiveRenderPath>, rcp<RiveRenderPaint>>;
// Measure the speed of RiveRenderer::drawPath(), with a null render context.
class DrawRiveRenderPath : public Bench
{
protected:
int run() const final
{
for (int i = 0; i < 10; ++i)
{
m_nullContext->beginFrame({
.renderTargetWidth = m_renderTarget->width(),
.renderTargetHeight = m_renderTarget->height(),
});
for (const auto& [path, paint] : m_pathPaints)
{
m_renderer.drawPath(path.get(), paint.get());
}
m_nullContext->flush({.renderTarget = m_renderTarget.get()});
}
return 0;
}
std::vector<PathPaint> m_pathPaints;
std::unique_ptr<RenderContext> m_nullContext =
RenderContextNULL::MakeContext();
mutable RiveRenderer m_renderer{m_nullContext.get()};
rive::rcp<RenderTarget> m_renderTarget =
m_nullContext->static_impl_cast<RenderContextNULL>()->makeRenderTarget(
1600,
1600);
};
class SniffPathsRenderer : public Renderer
{
public:
SniffPathsRenderer(std::vector<PathPaint>* pathPaints,
bool allStrokes,
bool allRoundJoin,
float forcedFeather = 0) :
m_pathPaints(pathPaints),
m_allStrokes(allStrokes),
m_allRoundJoin(allRoundJoin),
m_forcedFeather(forcedFeather)
{}
void save() override {}
void restore() override {}
void transform(const Mat2D& matrix) override {}
void drawPath(RenderPath* path, RenderPaint* paint) override
{
auto renderPath = static_cast<RiveRenderPath*>(path);
auto renderPaint = static_cast<RiveRenderPaint*>(paint);
if (m_allStrokes)
{
renderPaint->style(RenderPaintStyle::stroke);
renderPaint->join(StrokeJoin::bevel);
renderPaint->thickness(2);
}
if (m_allRoundJoin)
{
renderPaint->join(StrokeJoin::round);
}
if (m_forcedFeather)
{
renderPaint->feather(m_forcedFeather);
renderPath->fillRule(FillRule::clockwise);
}
m_pathPaints->push_back({ref_rcp(renderPath), ref_rcp(renderPaint)});
}
void clipPath(RenderPath* path) override {}
void drawImage(const RenderImage*, ImageSampler, BlendMode, float) override
{}
void drawImageMesh(const RenderImage*,
ImageSampler,
rcp<RenderBuffer>,
rcp<RenderBuffer>,
rcp<RenderBuffer>,
uint32_t vertexCount,
uint32_t indexCount,
BlendMode,
float) override
{}
private:
std::vector<PathPaint>* m_pathPaints;
bool m_allStrokes;
bool m_allRoundJoin;
float m_forcedFeather;
};
// Measure the speed of RiveRenderer::drawPath() from the contents of a .riv
// file.
class DrawRiveRenderPaths : public DrawRiveRenderPath
{
public:
DrawRiveRenderPaths(bool allStrokes = false, bool allRoundJoin = false)
{
// Sniff paths out of a .riv file.
SniffPathsRenderer sniffer(&m_pathPaints, allStrokes, allRoundJoin);
rcp<File> rivFile =
File::import(assets::paper_riv(), m_nullContext.get());
std::unique_ptr<ArtboardInstance> artboard = rivFile->artboardDefault();
std::unique_ptr<Scene> scene = artboard->defaultScene();
scene->advanceAndApply(0);
scene->draw(&sniffer);
}
};
REGISTER_BENCH(DrawRiveRenderPaths);
// Measure the speed of RiveRenderer::drawPath() from the contents of a .riv
// file, all paths converted to strokes.
class DrawRiveRenderPathsAsStrokes : public DrawRiveRenderPaths
{
public:
DrawRiveRenderPathsAsStrokes() : DrawRiveRenderPaths(true) {}
};
REGISTER_BENCH(DrawRiveRenderPathsAsStrokes);
class DrawRiveRenderPathsAsRoundJoinStrokes : public DrawRiveRenderPaths
{
public:
DrawRiveRenderPathsAsRoundJoinStrokes() : DrawRiveRenderPaths(true, true) {}
};
REGISTER_BENCH(DrawRiveRenderPathsAsRoundJoinStrokes);
class DrawCustomPaths : public DrawRiveRenderPath
{
public:
void setup() final
{
for (int i = 0; i < 1000; ++i)
{
RawPath rawPath;
auto renderPath = static_rcp_cast<RiveRenderPath>(
m_nullContext->makeRenderPath(rawPath, FillRule::clockwise));
setupPath(renderPath.get());
auto renderPaint = static_rcp_cast<RiveRenderPaint>(
m_nullContext->makeRenderPaint());
setupPaint(renderPaint.get());
m_pathPaints.emplace_back(std::move(renderPath),
std::move(renderPaint));
}
}
protected:
virtual void setupPath(RiveRenderPath* path) = 0;
virtual void setupPaint(RiveRenderPaint* paint) {}
};
class DrawCustomStrokes : public DrawCustomPaths
{
public:
void setupPaint(RiveRenderPaint* paint) override
{
paint->style(RenderPaintStyle::stroke);
paint->thickness(2);
}
};
class DrawZeroChopStrokes : public DrawCustomStrokes
{
protected:
void setupPath(RiveRenderPath* path) final
{
path->moveTo(199, 1225);
for (int j = 0; j < 50; ++j)
{
path->cubicTo(197, 943, 349, 607, 549, 427);
path->cubicTo(349, 607, 197, 943, 199, 1225);
}
}
};
REGISTER_BENCH(DrawZeroChopStrokes);
class DrawOneChopStrokes : public DrawCustomStrokes
{
protected:
void setupPath(RiveRenderPath* path) final
{
for (int j = 0; j < 50; ++j)
{
path->cubicTo(100, 0, 50, 100, 100, 100);
path->cubicTo(0, -100, 200, 100, 0, 0);
}
}
};
REGISTER_BENCH(DrawOneChopStrokes);
class DrawTwoChopStrokes : public DrawCustomStrokes
{
protected:
void setupPath(RiveRenderPath* path) final
{
path->moveTo(460, 1060);
for (int j = 0; j < 50; ++j)
{
path->cubicTo(403, -320, 60, 660, 1181, 634);
path->cubicTo(60, 660, 403, -320, 460, 1060);
}
}
};
REGISTER_BENCH(DrawTwoChopStrokes);
class DrawOneCuspStrokes : public DrawCustomStrokes
{
protected:
void setupPath(RiveRenderPath* path) final
{
for (int j = 0; j < 50; ++j)
{
path->cubicTo(100, 100, 100, 0, 0, 100);
path->cubicTo(100, 0, 100, 100, 0, 0);
}
}
};
REGISTER_BENCH(DrawOneCuspStrokes);
class DrawTwoCuspStrokes : public DrawCustomStrokes
{
protected:
void setupPath(RiveRenderPath* path) final
{
for (int j = 0; j < 50; ++j)
{
path->cubicTo(100, 0, 50, 0, 150, 0);
path->cubicTo(50, 0, 100, 0, 0, 0);
}
}
};
class DrawFeatheredPaths : public DrawRiveRenderPath
{
public:
DrawFeatheredPaths(rive::Span<uint8_t> riv)
{
// Sniff paths out of a .riv file.
SniffPathsRenderer sniffer(&m_pathPaints,
/*allStrokes=*/false,
/*allRoundJoin=*/false,
/*forcedFeather=*/100);
rcp<File> rivFile = File::import(riv, m_nullContext.get());
std::unique_ptr<ArtboardInstance> artboard = rivFile->artboardDefault();
std::unique_ptr<Scene> scene = artboard->defaultScene();
scene->advanceAndApply(0);
scene->draw(&sniffer);
}
};
class DrawFeatheredPaths_paper : public DrawFeatheredPaths
{
public:
DrawFeatheredPaths_paper() : DrawFeatheredPaths(assets::paper_riv()) {}
};
REGISTER_BENCH(DrawFeatheredPaths_paper);
class DrawCustomFeathers : public DrawCustomPaths
{
public:
void setupPath(RiveRenderPath* path) final
{
path->fillRule(FillRule::clockwise);
for (int j = 0; j < 50; ++j)
{
path->cubicTo(-800, 1600, 2400, 1600, 1600, 0);
}
}
void setupPaint(RiveRenderPaint* paint) override
{
paint->style(RenderPaintStyle::fill);
paint->feather(85);
}
};
REGISTER_BENCH(DrawCustomFeathers);
REGISTER_BENCH(DrawTwoCuspStrokes);