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}