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