odin-blend2d

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

renderjobproc_p.h (9410B)


      1 // This file is part of Blend2D project <https://blend2d.com>
      2 //
      3 // See blend2d.h or LICENSE.md for license and copyright information
      4 // SPDX-License-Identifier: Zlib
      5 
      6 #ifndef BLEND2D_RASTER_RENDERJOBPROC_P_H_INCLUDED
      7 #define BLEND2D_RASTER_RENDERJOBPROC_P_H_INCLUDED
      8 
      9 #include "../path_p.h"
     10 #include "../pathstroke_p.h"
     11 #include "../raster/edgebuilder_p.h"
     12 #include "../raster/rendercommand_p.h"
     13 #include "../raster/rastercontextops_p.h"
     14 #include "../raster/rasterdefs_p.h"
     15 #include "../raster/renderjob_p.h"
     16 
     17 //! \cond INTERNAL
     18 //! \addtogroup blend2d_raster_engine_impl
     19 //! \{
     20 
     21 namespace bl::RasterEngine {
     22 namespace JobProc {
     23 
     24 // bl::RasterEngine - Job Processor - State Accessor
     25 // =================================================
     26 
     27 namespace {
     28 
     29 class JobStateAccessor {
     30 public:
     31   const RenderJob_BaseOp* job;
     32 
     33   BL_INLINE_NODEBUG explicit JobStateAccessor(const RenderJob_BaseOp* job) noexcept
     34     : job(job) {}
     35 
     36   BL_INLINE_NODEBUG const SharedFillState* fill_state() const noexcept {
     37     return job->fill_state();
     38   }
     39 
     40   BL_INLINE const SharedBaseStrokeState* base_stroke_state() const noexcept {
     41     BL_ASSERT(job->stroke_state());
     42     return job->stroke_state();
     43   }
     44 
     45   BL_INLINE const SharedExtendedStrokeState* ext_stroke_state() const noexcept {
     46     BL_ASSERT(stroke_options().transform_order != BL_STROKE_TRANSFORM_ORDER_AFTER);
     47     return static_cast<const SharedExtendedStrokeState*>(job->stroke_state());
     48   }
     49 
     50   // Fill states.
     51   BL_INLINE_NODEBUG BLTransformType final_transform_fixed_type() const noexcept { return job->final_transform_fixed_type(); }
     52 
     53   BL_INLINE BLMatrix2D final_transform_fixed(const BLPoint& origin_fixed) const noexcept {
     54     const Matrix2x2& t = fill_state()->final_transform_fixed;
     55     return BLMatrix2D(t.m[0], t.m[1], t.m[2], t.m[3], origin_fixed.x, origin_fixed.y);
     56   }
     57 
     58   BL_INLINE_NODEBUG const BLBox& final_clip_box_fixed_d() const noexcept { return fill_state()->final_clip_box_fixed_d; }
     59 
     60   // Stroke states.
     61   BL_INLINE_NODEBUG const BLApproximationOptions& approximation_options() const noexcept { return base_stroke_state()->approximation_options; }
     62   BL_INLINE_NODEBUG const BLStrokeOptions& stroke_options() const noexcept { return base_stroke_state()->stroke_options; }
     63 
     64   BL_INLINE_NODEBUG BLTransformType meta_transform_fixed_type() const noexcept { return job->meta_transform_fixed_type(); }
     65 
     66   BL_INLINE BLMatrix2D meta_transform_fixed(const BLPoint& origin_fixed) const noexcept {
     67     const Matrix2x2& t = ext_stroke_state()->meta_transform_fixed;
     68     return BLMatrix2D(t.m[0], t.m[1], t.m[2], t.m[3], origin_fixed.x, origin_fixed.y);
     69   }
     70 
     71   BL_INLINE BLMatrix2D user_transform() const noexcept {
     72     const Matrix2x2& t = ext_stroke_state()->user_transform;
     73     return BLMatrix2D(t.m[0], t.m[1], t.m[2], t.m[3], 0.0, 0.0);
     74   }
     75 };
     76 
     77 } // {anonymous}
     78 
     79 // bl::RasterEngine - Job Processor - Utilities
     80 // ============================================
     81 
     82 static BL_INLINE void prepare_edge_builder(WorkData* work_data, const SharedFillState* fill_state) noexcept {
     83   work_data->save_state();
     84   work_data->edge_builder.set_clip_box(fill_state->final_clip_box_fixed_d);
     85   work_data->edge_builder.set_flatten_tolerance_sq(Math::square(fill_state->toleranceFixedD));
     86 }
     87 
     88 static BL_INLINE BLPath* get_geometry_as_path(WorkData* work_data, RenderJob_GeometryOp* job) noexcept {
     89   BLPath* path = nullptr;
     90   BLGeometryType geometry_type = job->geometry_type();
     91 
     92   if (geometry_type == BL_GEOMETRY_TYPE_PATH)
     93     return job->geometry_data<BLPath>();
     94 
     95   path = &work_data->tmp_path[3];
     96   path->clear();
     97   BLResult result = path->add_geometry(geometry_type, job->geometry_data<void>());
     98 
     99   if (result != BL_SUCCESS) {
    100     work_data->accumulate_error(result);
    101     return nullptr;
    102   }
    103 
    104   return path;
    105 }
    106 
    107 static BL_INLINE void finalize_geometry_data(WorkData* work_data, RenderJob_GeometryOp* job) noexcept {
    108   bl_unused(work_data);
    109   if (job->geometry_type() == BL_GEOMETRY_TYPE_PATH)
    110     job->geometry_data<BLPath>()->~BLPath();
    111 }
    112 
    113 template<typename Job>
    114 static BL_INLINE void assign_edges(WorkData* work_data, Job* job, EdgeStorage<int>* edge_storage) noexcept {
    115   if (!edge_storage->is_empty()) {
    116     RenderCommandQueue* command_queue = job->command_queue();
    117     size_t command_index = job->command_index();
    118     uint8_t qy0 = uint8_t((edge_storage->bounding_box().y0) >> work_data->command_quantization_shift_fp());
    119 
    120     command_queue->initQuantizedY0(command_index, qy0);
    121     command_queue->at(command_index).set_analytic_edges(edge_storage);
    122     edge_storage->reset_bounding_box();
    123   }
    124 }
    125 
    126 // bl::RasterEngine - Job Processor - Fill Geometry Job
    127 // ====================================================
    128 
    129 static void process_fill_geometry_job(WorkData* work_data, RenderJob_GeometryOp* job) noexcept {
    130   BLPath* path = get_geometry_as_path(work_data, job);
    131   if (BL_UNLIKELY(!path))
    132     return;
    133 
    134   JobStateAccessor accessor(job);
    135   prepare_edge_builder(work_data, accessor.fill_state());
    136   BLResult result = add_filled_path_edges(work_data, path->view(), accessor.final_transform_fixed(job->origin_fixed()), accessor.final_transform_fixed_type());
    137 
    138   if (result == BL_SUCCESS) {
    139     assign_edges(work_data, job, &work_data->edge_storage);
    140   }
    141 
    142   finalize_geometry_data(work_data, job);
    143 }
    144 
    145 // bl::RasterEngine - Job Processor - Fill Text Job
    146 // ================================================
    147 
    148 static void process_fill_text_job(WorkData* work_data, RenderJob_TextOp* job) noexcept {
    149   BLResult result = BL_SUCCESS;
    150   uint32_t data_type = job->text_data_type();
    151 
    152   const BLFont& font = job->_font.dcast();
    153   const BLPoint& origin_fixed = job->origin_fixed();
    154   const BLGlyphRun* glyph_run = nullptr;
    155 
    156   if (data_type != RenderJob::kTextDataGlyphRun) {
    157     BLGlyphBuffer* glyph_buffer;
    158 
    159     if (data_type != RenderJob::kTextDataGlyphBuffer) {
    160       glyph_buffer = &work_data->glyph_buffer;
    161       glyph_buffer->set_text(job->text_data(), job->text_size(), (BLTextEncoding)data_type);
    162     }
    163     else {
    164       glyph_buffer = &job->_glyph_buffer.dcast();
    165     }
    166 
    167     result = font.shape(*glyph_buffer);
    168     glyph_run = &glyph_buffer->glyph_run();
    169   }
    170   else {
    171     glyph_run = &job->_glyph_run;
    172   }
    173 
    174   if (result == BL_SUCCESS) {
    175     JobStateAccessor accessor(job);
    176     prepare_edge_builder(work_data, accessor.fill_state());
    177 
    178     result = add_filled_glyph_run_edges(work_data, accessor, origin_fixed, &font, glyph_run);
    179     if (result == BL_SUCCESS) {
    180       assign_edges(work_data, job, &work_data->edge_storage);
    181     }
    182   }
    183 
    184   job->destroy();
    185 }
    186 
    187 // bl::RasterEngine - Job Processor - Stroke Geometry Job
    188 // ======================================================
    189 
    190 static void process_stroke_geometry_job(WorkData* work_data, RenderJob_GeometryOp* job) noexcept {
    191   BLPath* path = get_geometry_as_path(work_data, job);
    192   if (BL_UNLIKELY(!path))
    193     return;
    194 
    195   JobStateAccessor accessor(job);
    196   prepare_edge_builder(work_data, accessor.fill_state());
    197 
    198   if (add_stroked_path_edges(work_data, accessor, job->origin_fixed(), path) == BL_SUCCESS) {
    199     assign_edges(work_data, job, &work_data->edge_storage);
    200   }
    201 
    202   finalize_geometry_data(work_data, job);
    203 }
    204 
    205 // bl::RasterEngine - Job Processor - Stroke Text Job
    206 // ==================================================
    207 
    208 static void process_stroke_text_job(WorkData* work_data, RenderJob_TextOp* job) noexcept {
    209   BLResult result = BL_SUCCESS;
    210   uint32_t data_type = job->text_data_type();
    211 
    212   const BLFont& font = job->_font.dcast();
    213   const BLPoint& origin_fixed = job->origin_fixed();
    214   const BLGlyphRun* glyph_run = nullptr;
    215 
    216   if (data_type != RenderJob::kTextDataGlyphRun) {
    217     BLGlyphBuffer* glyph_buffer;
    218 
    219     if (data_type != RenderJob::kTextDataGlyphBuffer) {
    220       glyph_buffer = &work_data->glyph_buffer;
    221       glyph_buffer->set_text(job->text_data(), job->text_size(), (BLTextEncoding)data_type);
    222     }
    223     else {
    224       glyph_buffer = &job->_glyph_buffer.dcast();
    225     }
    226 
    227     result = font.shape(*glyph_buffer);
    228     glyph_run = &glyph_buffer->glyph_run();
    229   }
    230   else {
    231     glyph_run = &job->_glyph_run;
    232   }
    233 
    234   if (result == BL_SUCCESS) {
    235     JobStateAccessor accessor(job);
    236     prepare_edge_builder(work_data, accessor.fill_state());
    237 
    238     result = add_stroked_glyph_run_edges(work_data, accessor, origin_fixed, &font, glyph_run);
    239     if (result == BL_SUCCESS) {
    240       assign_edges(work_data, job, &work_data->edge_storage);
    241     }
    242   }
    243 
    244   job->destroy();
    245 }
    246 
    247 // bl::RasterEngine - Job Processor - Dispatch
    248 // ===========================================
    249 
    250 static void process_job(WorkData* work_data, RenderJob* job) noexcept {
    251   if (job->has_job_flag(RenderJobFlags::kComputePendingFetchData)) {
    252     RenderCommand& command = job->command();
    253     compute_pending_fetch_data(command._source.fetch_data);
    254   }
    255 
    256   switch (job->job_type()) {
    257     case RenderJobType::kFillGeometry:
    258       process_fill_geometry_job(work_data, static_cast<RenderJob_GeometryOp*>(job));
    259       break;
    260 
    261     case RenderJobType::kFillText:
    262       process_fill_text_job(work_data, static_cast<RenderJob_TextOp*>(job));
    263       break;
    264 
    265     case RenderJobType::kStrokeGeometry:
    266       process_stroke_geometry_job(work_data, static_cast<RenderJob_GeometryOp*>(job));
    267       break;
    268 
    269     case RenderJobType::kStrokeText:
    270       process_stroke_text_job(work_data, static_cast<RenderJob_TextOp*>(job));
    271       break;
    272 
    273     default:
    274       BL_NOT_REACHED();
    275   }
    276 }
    277 
    278 } // {JobProc}
    279 } // {bl::RasterEngine}
    280 
    281 //! \}
    282 //! \endcond
    283 
    284 #endif // BLEND2D_RASTER_RENDERJOBPROC_P_H_INCLUDED