odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

bl_bench_backend_blend2d.cpp (18041B)


      1 // This file is part of Blend2D project <https://blend2d.com>
      2 //
      3 // See LICENSE.md for license and copyright information
      4 // SPDX-License-Identifier: Zlib
      5 
      6 #include "bl_bench_app.h"
      7 #include "bl_bench_backend.h"
      8 
      9 #include <blend2d.h>
     10 #include <stdio.h>
     11 
     12 namespace blbench {
     13 
     14 class Blend2DModule : public Backend {
     15 public:
     16 
     17   BLContext _context;
     18   uint32_t _threadCount;
     19   uint32_t _cpu_features;
     20 
     21   // Initialized by before_run().
     22   BLGradientType _gradient_type;
     23   BLExtendMode _gradient_extend;
     24 
     25   // Construction & Destruction
     26   // --------------------------
     27 
     28   explicit Blend2DModule(uint32_t thread_count = 0, uint32_t cpu_features = 0);
     29   ~Blend2DModule() override;
     30 
     31   // Interface
     32   // ---------
     33 
     34   void serialize_info(JSONBuilder& json) const override;
     35 
     36   bool supports_comp_op(BLCompOp comp_op) const override;
     37   bool supports_style(StyleKind style) const override;
     38 
     39   void before_run() override;
     40   void flush() override;
     41   void after_run() override;
     42 
     43   template<typename RectT>
     44   inline const BLVar& setup_style(const RectT& rect, StyleKind style, BLGradient& gradient, BLPattern& pattern);
     45 
     46   void render_rect_a(RenderOp op) override;
     47   void render_rect_f(RenderOp op) override;
     48   void render_rect_rotated(RenderOp op) override;
     49   void render_round_f(RenderOp op) override;
     50   void render_round_rotated(RenderOp op) override;
     51   void render_polygon(RenderOp op, uint32_t complexity) override;
     52   void render_shape(RenderOp op, ShapeData shape) override;
     53 };
     54 
     55 Blend2DModule::Blend2DModule(uint32_t thread_count, uint32_t cpu_features) {
     56   _threadCount = thread_count;
     57   _cpu_features = cpu_features;
     58 
     59   const char* feature = nullptr;
     60 
     61   if (_cpu_features == 0xFFFFFFFFu) {
     62     feature = "[NO JIT]";
     63   }
     64   else {
     65     if (_cpu_features & BL_RUNTIME_CPU_FEATURE_X86_SSE2  ) feature = "[SSE2]";
     66     if (_cpu_features & BL_RUNTIME_CPU_FEATURE_X86_SSE3  ) feature = "[SSE3]";
     67     if (_cpu_features & BL_RUNTIME_CPU_FEATURE_X86_SSSE3 ) feature = "[SSSE3]";
     68     if (_cpu_features & BL_RUNTIME_CPU_FEATURE_X86_SSE4_1) feature = "[SSE4.1]";
     69     if (_cpu_features & BL_RUNTIME_CPU_FEATURE_X86_SSE4_2) feature = "[SSE4.2]";
     70     if (_cpu_features & BL_RUNTIME_CPU_FEATURE_X86_AVX   ) feature = "[AVX]";
     71     if (_cpu_features & BL_RUNTIME_CPU_FEATURE_X86_AVX2  ) feature = "[AVX2]";
     72     if (_cpu_features & BL_RUNTIME_CPU_FEATURE_X86_AVX512) feature = "[AVX512]";
     73   }
     74 
     75   if (!_threadCount)
     76     snprintf(_name, sizeof(_name), "Blend2D ST%s%s", feature ? " " : "", feature ? feature : "");
     77   else
     78     snprintf(_name, sizeof(_name), "Blend2D %uT%s%s", _threadCount, feature ? " " : "", feature ? feature : "");
     79 }
     80 
     81 Blend2DModule::~Blend2DModule() {}
     82 
     83 void Blend2DModule::serialize_info(JSONBuilder& json) const {
     84   BLRuntimeBuildInfo build_info;
     85   BLRuntime::query_build_info(&build_info);
     86 
     87   json.before_record()
     88       .add_key("version")
     89       .add_stringf("%u.%u.%u", build_info.major_version, build_info.minor_version, build_info.patch_version);
     90 }
     91 
     92 template<typename RectT>
     93 inline const BLVar& Blend2DModule::setup_style(const RectT& rect, StyleKind style, BLGradient& gradient, BLPattern& pattern) {
     94   if (style <= StyleKind::kConic) {
     95     BLRgba32 c0(_rnd_color.next_rgba32());
     96     BLRgba32 c1(_rnd_color.next_rgba32());
     97     BLRgba32 c2(_rnd_color.next_rgba32());
     98 
     99     switch (style) {
    100       case StyleKind::kLinearPad:
    101       case StyleKind::kLinearRepeat:
    102       case StyleKind::kLinearReflect: {
    103         BLLinearGradientValues values {};
    104         values.x0 = rect.x + rect.w * 0.2;
    105         values.y0 = rect.y + rect.h * 0.2;
    106         values.x1 = rect.x + rect.w * 0.8;
    107         values.y1 = rect.y + rect.h * 0.8;
    108 
    109         gradient.set_values(values);
    110         gradient.reset_stops();
    111         gradient.add_stop(0.0, c0);
    112         gradient.add_stop(0.5, c1);
    113         gradient.add_stop(1.0, c2);
    114         break;
    115       }
    116 
    117       case StyleKind::kRadialPad:
    118       case StyleKind::kRadialRepeat:
    119       case StyleKind::kRadialReflect: {
    120         BLRadialGradientValues values {};
    121         values.x0 = rect.x + (rect.w / 2);
    122         values.y0 = rect.y + (rect.h / 2);
    123         values.r0 = (rect.w + rect.h) / 4;
    124         values.x1 = values.x0 - values.r0 / 2.0;
    125         values.y1 = values.y0 - values.r0 / 2.0;
    126 
    127         gradient.set_values(values);
    128         gradient.reset_stops();
    129         gradient.add_stop(0.0, c0);
    130         gradient.add_stop(0.5, c1);
    131         gradient.add_stop(1.0, c2);
    132         break;
    133       }
    134 
    135       default: {
    136         BLConicGradientValues values {};
    137         values.x0 = rect.x + (rect.w / 2);
    138         values.y0 = rect.y + (rect.h / 2);
    139         values.angle = 0;
    140         values.repeat = 1;
    141 
    142         gradient.set_values(values);
    143         gradient.reset_stops();
    144 
    145         gradient.add_stop(0.00, c0);
    146         gradient.add_stop(0.33, c1);
    147         gradient.add_stop(0.66, c2);
    148         gradient.add_stop(1.00, c0);
    149         break;
    150       }
    151     }
    152     return reinterpret_cast<const BLVar&>(gradient);
    153   }
    154   else {
    155     pattern.create(_sprites[nextSpriteId()], BL_EXTEND_MODE_REPEAT, BLMatrix2D::make_translation(rect.x, rect.y));
    156     return reinterpret_cast<const BLVar&>(pattern);
    157   }
    158 }
    159 
    160 bool Blend2DModule::supports_comp_op(BLCompOp comp_op) const {
    161   // This backend supports all composition operators.
    162   (void)comp_op;
    163 
    164   return true;
    165 }
    166 
    167 bool Blend2DModule::supports_style(StyleKind style) const {
    168   // This backend supports all styles.
    169   (void)style;
    170 
    171   return true;
    172 }
    173 
    174 void Blend2DModule::before_run() {
    175   int w = int(_params.screen_w);
    176   int h = int(_params.screen_h);
    177   StyleKind style = _params.style;
    178 
    179   BLContextCreateInfo create_info {};
    180   create_info.thread_count = _threadCount;
    181 
    182   if (_cpu_features == 0xFFFFFFFFu) {
    183     create_info.flags = BL_CONTEXT_CREATE_FLAG_DISABLE_JIT;
    184   }
    185   else  if (_cpu_features) {
    186     create_info.flags = BL_CONTEXT_CREATE_FLAG_ISOLATED_JIT_RUNTIME |
    187                         BL_CONTEXT_CREATE_FLAG_OVERRIDE_CPU_FEATURES;
    188     create_info.cpu_features = _cpu_features;
    189   }
    190 
    191   _surface.create(w, h, _params.format);
    192   _context.begin(_surface, &create_info);
    193 
    194   _context.set_comp_op(BL_COMP_OP_SRC_COPY);
    195   _context.fill_all(BLRgba32(0x00000000));
    196 
    197   _context.set_comp_op(_params.comp_op);
    198   _context.set_stroke_width(_params.stroke_width);
    199 
    200   _context.set_pattern_quality(
    201     _params.style == StyleKind::kPatternNN
    202       ? BL_PATTERN_QUALITY_NEAREST
    203       : BL_PATTERN_QUALITY_BILINEAR);
    204 
    205   // Setup globals.
    206   _gradient_type = BL_GRADIENT_TYPE_LINEAR;
    207   _gradient_extend = BL_EXTEND_MODE_PAD;
    208 
    209   switch (style) {
    210     case StyleKind::kLinearPad    : _gradient_type = BL_GRADIENT_TYPE_LINEAR; _gradient_extend = BL_EXTEND_MODE_PAD    ; break;
    211     case StyleKind::kLinearRepeat : _gradient_type = BL_GRADIENT_TYPE_LINEAR; _gradient_extend = BL_EXTEND_MODE_REPEAT ; break;
    212     case StyleKind::kLinearReflect: _gradient_type = BL_GRADIENT_TYPE_LINEAR; _gradient_extend = BL_EXTEND_MODE_REFLECT; break;
    213     case StyleKind::kRadialPad    : _gradient_type = BL_GRADIENT_TYPE_RADIAL; _gradient_extend = BL_EXTEND_MODE_PAD    ; break;
    214     case StyleKind::kRadialRepeat : _gradient_type = BL_GRADIENT_TYPE_RADIAL; _gradient_extend = BL_EXTEND_MODE_REPEAT ; break;
    215     case StyleKind::kRadialReflect: _gradient_type = BL_GRADIENT_TYPE_RADIAL; _gradient_extend = BL_EXTEND_MODE_REFLECT; break;
    216     case StyleKind::kConic        : _gradient_type = BL_GRADIENT_TYPE_CONIC; break;
    217 
    218     default:
    219       break;
    220   }
    221 
    222   _context.flush(BL_CONTEXT_FLUSH_SYNC);
    223 }
    224 
    225 void Blend2DModule::flush() {
    226   _context.flush(BL_CONTEXT_FLUSH_SYNC);
    227 }
    228 
    229 void Blend2DModule::after_run() {
    230   _context.end();
    231 }
    232 
    233 void Blend2DModule::render_rect_a(RenderOp op) {
    234   BLSizeI bounds(int(_params.screen_w), int(_params.screen_h));
    235   StyleKind style = _params.style;
    236   int wh = int(_params.shape_size);
    237 
    238   if (style == StyleKind::kSolid) {
    239     for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) {
    240       BLRectI rect(_rnd_coord.next_rect_i(bounds, wh, wh));
    241       BLRgba32 color(_rnd_color.next_rgba32());
    242 
    243       if (op == RenderOp::kStroke)
    244         _context.stroke_rect(BLRect(rect.x, rect.y, rect.w, rect.h), color);
    245       else
    246         _context.fill_rect(rect, color);
    247     }
    248   }
    249   else if ((style == StyleKind::kPatternNN || style == StyleKind::kPatternBI) && op != RenderOp::kStroke) {
    250     for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) {
    251       BLRectI rect(_rnd_coord.next_rect_i(bounds, wh, wh));
    252       _context.blit_image(BLPointI(rect.x, rect.y), _sprites[nextSpriteId()]);
    253     }
    254   }
    255   else {
    256     BLPattern pattern;
    257     BLGradient gradient(_gradient_type);
    258     gradient.set_extend_mode(_gradient_extend);
    259 
    260     for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) {
    261       BLRectI rect(_rnd_coord.next_rect_i(bounds, wh, wh));
    262       const auto& obj = setup_style(rect, style, gradient, pattern);
    263 
    264       if (op == RenderOp::kStroke)
    265         _context.stroke_rect(BLRect(rect.x, rect.y, rect.w, rect.h), obj);
    266       else
    267         _context.fill_rect(rect, obj);
    268     }
    269   }
    270 }
    271 
    272 void Blend2DModule::render_rect_f(RenderOp op) {
    273   BLSize bounds(_params.screen_w, _params.screen_h);
    274   StyleKind style = _params.style;
    275   double wh = double(_params.shape_size);
    276 
    277   if (style == StyleKind::kSolid) {
    278     for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) {
    279       BLRect rect(_rnd_coord.next_rect(bounds, wh, wh));
    280       BLRgba32 color(_rnd_color.next_rgba32());
    281 
    282       if (op == RenderOp::kStroke)
    283         _context.stroke_rect(rect, color);
    284       else
    285         _context.fill_rect(rect, color);
    286     }
    287   }
    288   else if ((style == StyleKind::kPatternNN || style == StyleKind::kPatternBI) && op != RenderOp::kStroke) {
    289     for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) {
    290       BLRect rect(_rnd_coord.next_rect(bounds, wh, wh));
    291       _context.blit_image(BLPoint(rect.x, rect.y), _sprites[nextSpriteId()]);
    292     }
    293   }
    294   else {
    295     BLPattern pattern;
    296     BLGradient gradient(_gradient_type);
    297     gradient.set_extend_mode(_gradient_extend);
    298 
    299     for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) {
    300       BLRect rect(_rnd_coord.next_rect(bounds, wh, wh));
    301       const auto& obj = setup_style(rect, style, gradient, pattern);
    302 
    303       if (op == RenderOp::kStroke)
    304         _context.stroke_rect(rect, obj);
    305       else
    306         _context.fill_rect(rect, obj);
    307     }
    308   }
    309 }
    310 
    311 void Blend2DModule::render_rect_rotated(RenderOp op) {
    312   BLSize bounds(_params.screen_w, _params.screen_h);
    313   StyleKind style = _params.style;
    314 
    315   double cx = double(_params.screen_w) * 0.5;
    316   double cy = double(_params.screen_h) * 0.5;
    317   double wh = double(_params.shape_size);
    318   double angle = 0.0;
    319 
    320   if (style == StyleKind::kSolid) {
    321     for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++, angle += 0.01) {
    322       BLRect rect(_rnd_coord.next_rect(bounds, wh, wh));
    323       BLRgba32 color(_rnd_color.next_rgba32());
    324 
    325       _context.rotate(angle, BLPoint(cx, cy));
    326 
    327       if (op == RenderOp::kStroke)
    328         _context.stroke_rect(rect, color);
    329       else
    330         _context.fill_rect(rect, color);
    331 
    332       _context.reset_transform();
    333     }
    334   }
    335   else if ((style == StyleKind::kPatternNN || style == StyleKind::kPatternBI) && op != RenderOp::kStroke) {
    336     for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++, angle += 0.01) {
    337       BLRect rect(_rnd_coord.next_rect(bounds, wh, wh));
    338 
    339       _context.save();
    340       _context.rotate(angle, BLPoint(cx, cy));
    341       _context.blit_image(BLPoint(rect.x, rect.y), _sprites[nextSpriteId()]);
    342       _context.restore();
    343     }
    344   }
    345   else {
    346     BLPattern pattern;
    347     BLGradient gradient(_gradient_type);
    348     gradient.set_extend_mode(_gradient_extend);
    349 
    350     for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++, angle += 0.01) {
    351       BLRect rect(_rnd_coord.next_rect(bounds, wh, wh));
    352       const auto& obj = setup_style(rect, style, gradient, pattern);
    353 
    354       _context.save();
    355       _context.rotate(angle, BLPoint(cx, cy));
    356 
    357       if (op == RenderOp::kStroke)
    358         _context.stroke_rect(rect, obj);
    359       else
    360         _context.fill_rect(rect, obj);
    361 
    362       _context.restore();
    363     }
    364   }
    365 }
    366 
    367 void Blend2DModule::render_round_f(RenderOp op) {
    368   BLSize bounds(_params.screen_w, _params.screen_h);
    369   StyleKind style = _params.style;
    370   double wh = double(_params.shape_size);
    371 
    372   if (style == StyleKind::kSolid) {
    373     for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) {
    374       double radius = _rnd_extra.next_double(4.0, 40.0);
    375       BLRect rect(_rnd_coord.next_rect(bounds, wh, wh));
    376       BLRoundRect round(rect, radius);
    377 
    378       BLRgba32 color(_rnd_color.next_rgba32());
    379       if (op == RenderOp::kStroke)
    380         _context.stroke_round_rect(round, color);
    381       else
    382         _context.fill_round_rect(round, color);
    383     }
    384   }
    385   else {
    386     BLPattern pattern;
    387     BLGradient gradient(_gradient_type);
    388     gradient.set_extend_mode(_gradient_extend);
    389 
    390     for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) {
    391       double radius = _rnd_extra.next_double(4.0, 40.0);
    392       BLRect rect(_rnd_coord.next_rect(bounds, wh, wh));
    393       BLRoundRect round(rect, radius);
    394 
    395       const auto& obj = setup_style(rect, style, gradient, pattern);
    396       if (op == RenderOp::kStroke)
    397         _context.stroke_round_rect(round, obj);
    398       else
    399         _context.fill_round_rect(round, obj);
    400     }
    401   }
    402 }
    403 
    404 void Blend2DModule::render_round_rotated(RenderOp op) {
    405   BLSize bounds(_params.screen_w, _params.screen_h);
    406   StyleKind style = _params.style;
    407 
    408   double cx = double(_params.screen_w) * 0.5;
    409   double cy = double(_params.screen_h) * 0.5;
    410   double wh = double(_params.shape_size);
    411   double angle = 0.0;
    412 
    413   if (style == StyleKind::kSolid) {
    414     for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++, angle += 0.01) {
    415       double radius = _rnd_extra.next_double(4.0, 40.0);
    416       BLRect rect(_rnd_coord.next_rect(bounds, wh, wh));
    417       BLRoundRect round(rect, radius);
    418 
    419       _context.rotate(angle, BLPoint(cx, cy));
    420       BLRgba32 color(_rnd_color.next_rgba32());
    421 
    422       if (op == RenderOp::kStroke)
    423         _context.stroke_round_rect(round, color);
    424       else
    425         _context.fill_round_rect(round, color);
    426 
    427       _context.reset_transform();
    428     }
    429   }
    430   else {
    431     BLPattern pattern;
    432     BLGradient gradient(_gradient_type);
    433     gradient.set_extend_mode(_gradient_extend);
    434 
    435     for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++, angle += 0.01) {
    436       double radius = _rnd_extra.next_double(4.0, 40.0);
    437       BLRect rect(_rnd_coord.next_rect(bounds, wh, wh));
    438       BLRoundRect round(rect, radius);
    439 
    440       const auto& obj = setup_style(rect, style, gradient, pattern);
    441 
    442       _context.save();
    443       _context.rotate(angle, BLPoint(cx, cy));
    444 
    445       if (op == RenderOp::kStroke)
    446         _context.stroke_round_rect(round, obj);
    447       else
    448         _context.fill_round_rect(round, obj);
    449 
    450       _context.restore();
    451     }
    452   }
    453 }
    454 
    455 void Blend2DModule::render_polygon(RenderOp op, uint32_t complexity) {
    456   static constexpr uint32_t kPointCapacity = 128;
    457 
    458   if (complexity > kPointCapacity)
    459     return;
    460 
    461   BLSizeI bounds(
    462     int(_params.screen_w - _params.shape_size),
    463     int(_params.screen_h - _params.shape_size));
    464   StyleKind style = _params.style;
    465   double wh = double(_params.shape_size);
    466 
    467   BLPoint points[kPointCapacity];
    468   BLPattern pattern;
    469   BLGradient gradient(_gradient_type);
    470 
    471   _context.set_fill_rule(op == RenderOp::kFillEvenOdd ? BL_FILL_RULE_EVEN_ODD : BL_FILL_RULE_NON_ZERO);
    472   gradient.set_extend_mode(_gradient_extend);
    473 
    474   for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) {
    475     BLPoint base(_rnd_coord.nextPoint(bounds));
    476 
    477     for (uint32_t p = 0; p < complexity; p++) {
    478       double x = _rnd_coord.next_double(base.x, base.x + wh);
    479       double y = _rnd_coord.next_double(base.y, base.y + wh);
    480       points[p].reset(x, y);
    481     }
    482 
    483     if (style == StyleKind::kSolid) {
    484       BLRgba32 color = _rnd_color.next_rgba32();
    485       if (op == RenderOp::kStroke)
    486         _context.stroke_polygon(points, complexity, color);
    487       else
    488         _context.fill_polygon(points, complexity, color);
    489     }
    490     else {
    491       BLRect rect(base.x, base.y, wh, wh);
    492       const auto& obj = setup_style(rect, style, gradient, pattern);
    493 
    494       if (op == RenderOp::kStroke)
    495         _context.stroke_polygon(points, complexity, obj);
    496       else
    497         _context.fill_polygon(points, complexity, obj);
    498     }
    499   }
    500 }
    501 
    502 void Blend2DModule::render_shape(RenderOp op, ShapeData shape) {
    503   BLSizeI bounds(
    504     int(_params.screen_w - _params.shape_size),
    505     int(_params.screen_h - _params.shape_size));
    506   StyleKind style = _params.style;
    507   double wh = double(_params.shape_size);
    508 
    509   BLPath path;
    510   ShapeIterator it(shape);
    511 
    512   while (it.has_command()) {
    513     if (it.is_move_to()) {
    514       path.move_to(it.vertex(0));
    515     }
    516     else if (it.is_line_to()) {
    517       path.line_to(it.vertex(0));
    518     }
    519     else if (it.is_quad_to()) {
    520       path.quad_to(it.vertex(0), it.vertex(1));
    521     }
    522     else if (it.is_cubic_to()) {
    523       path.cubic_to(it.vertex(0), it.vertex(1), it.vertex(2));
    524     }
    525     else {
    526       path.close();
    527     }
    528     it.next();
    529   }
    530 
    531   path.transform(BLMatrix2D::make_scaling(wh, wh));
    532 
    533   BLPattern pattern;
    534   BLGradient gradient(_gradient_type);
    535 
    536   _context.set_fill_rule(op == RenderOp::kFillEvenOdd ? BL_FILL_RULE_EVEN_ODD : BL_FILL_RULE_NON_ZERO);
    537   gradient.set_extend_mode(_gradient_extend);
    538 
    539   for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) {
    540     BLPoint base(_rnd_coord.nextPoint(bounds));
    541 
    542     if (style == StyleKind::kSolid) {
    543       BLRgba32 color = _rnd_color.next_rgba32();
    544       if (op == RenderOp::kStroke)
    545         _context.stroke_path(base, path, color);
    546       else
    547         _context.fill_path(base, path, color);
    548     }
    549     else {
    550       BLRect rect(base.x, base.y, wh, wh);
    551       const auto& obj = setup_style(rect, style, gradient, pattern);
    552 
    553       if (op == RenderOp::kStroke)
    554         _context.stroke_path(base, path, obj);
    555       else
    556         _context.fill_path(base, path, obj);
    557     }
    558   }
    559 }
    560 
    561 Backend* create_blend2d_backend(uint32_t thread_count, uint32_t cpu_features) {
    562   return new Blend2DModule(thread_count, cpu_features);
    563 }
    564 
    565 } // {blbench}