Arm-2D  
2D Image Processing Library for Cortex-M Processors
arm_2d_helper_pfb.h
1/*
2 * Copyright (C) 2022 Arm Limited or its affiliates. All rights reserved.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19/* ----------------------------------------------------------------------
20 * Project: Arm-2D Library
21 * Title: #include "arm_2d_helper_pfb.h"
22 * Description: Public header file for the PFB helper service
23 *
24 * $Date: 17. June 2022
25 * $Revision: V.1.0.1
26 *
27 * Target Processor: Cortex-M cores
28 * -------------------------------------------------------------------- */
29#ifndef __ARM_2D_HELPER_PFB_H__
30#define __ARM_2D_HELPER_PFB_H__
31
32/*============================ INCLUDES ======================================*/
33#include "arm_2d.h"
34
35#ifdef __cplusplus
36extern "C" {
37#endif
38
39
40#if defined(__clang__)
41# pragma clang diagnostic push
42# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
43# pragma clang diagnostic ignored "-Wpadded"
44#endif
45
46
47/*!
48 * \addtogroup gHelper 7 Helper Services
49 * @{
50 */
51
52/*============================ MACROS ========================================*/
53/*============================ MACROFIED FUNCTIONS ===========================*/
54
55/*!
56 * \brief a macro wrapper in uppercase to help initialising PFB service
57 * \param[in] __CB_ADDR the address of the arm_2d_helper_pfb_t object
58 * \param[in] __SCREEN_WIDTH the width of the screen
59 * \param[in] __SCREEN_HEIGHT the hight of the screen
60 * \param[in] __PIXEL_TYPE the integer type of the pixel, i.e. uint8_t, uint16_t,
61 * uint32_t
62 * \param[in] __WIDTH the width of the PFB block
63 * \param[in] __HEIGHT the height of the PFB block
64 * \note For the same number of pixels in a PFB block, please priority the width
65 * over height, for example, 240 * 1 is better than 30 * 8
66 * \param[in] __PFB_NUM the number of PFB blocks in the built-in PFB pool.
67 * \param[in] ... a code block to add additional initializer, see example below:
68 * \return arm_2d_err_t the result of the initialisation process
69 *
70 * \code {.c}
71
72 static ARM_NOINIT arm_2d_helper_pfb_t s_tExamplePFB;
73 ...
74 // initialise FPB helper
75 if (ARM_2D_HELPER_PFB_INIT(
76 &s_tExamplePFB, // FPB Helper object
77 __GLCD_CFG_SCEEN_WIDTH__, // screen width
78 __GLCD_CFG_SCEEN_HEIGHT__, // screen height
79 uint16_t, // colour date type
80 240, // PFB block width
81 1, // PFB block height
82 1, // number of PFB in the PFB pool
83 {
84 .evtOnLowLevelRendering = {
85 // callback for low level rendering
86 .fnHandler = &__pfb_render_handler,
87 },
88 .evtOnDrawing = {
89 // callback for drawing GUI
90 .fnHandler = &__pfb_draw_background_handler,
91 },
92 },
93 //.FrameBuffer.bSwapRGB16 = true,
94 ) < 0) {
95 //! error detected
96 assert(false);
97 }
98 * \endcode
99 *
100 */
101#define ARM_2D_HELPER_PFB_INIT( __CB_ADDR, /* PFB Helper object address */ \
102 __SCREEN_WIDTH, /* Screen width */ \
103 __SCREEN_HEIGHT,/* Screen height */ \
104 __PIXEL_TYPE, /* The type of the pixels */ \
105 __WIDTH, /* The width of the PFB block */\
106 __HEIGHT, /* The height of the PFB block*/\
107 __PFB_NUM, /* Block count in the PFB pool*/\
108 ... /* Event Handler */ \
109 ) \
110 ({ \
111 __attribute__((section(".bss.noinit.arm_2d_pfb_pool"))) \
112 static struct { \
113 arm_2d_pfb_t tFPB; \
114 __ALIGNED(4) \
115 __PIXEL_TYPE tBuffer[(__WIDTH) * (__HEIGHT)]; \
116 } s_tPFBs[__PFB_NUM]; \
117 \
118 arm_2d_helper_pfb_cfg_t tCFG = { \
119 .tDisplayArea.tSize = { \
120 .iWidth = (__SCREEN_WIDTH), \
121 .iHeight = (__SCREEN_HEIGHT), \
122 }, \
123 \
124 .FrameBuffer.ptPFBs = (arm_2d_pfb_t *)s_tPFBs, \
125 .FrameBuffer.tFrameSize = { \
126 .iWidth = (__WIDTH), \
127 .iHeight = (__HEIGHT), \
128 }, \
129 .FrameBuffer.wBufferSize = sizeof(s_tPFBs[0].tBuffer), \
130 .FrameBuffer.hwPFBNum = dimof(s_tPFBs), \
131 .Dependency = \
132 __VA_ARGS__ \
133 }; \
134 \
135 arm_2d_helper_pfb_init((__CB_ADDR), &tCFG); \
136 })
137
138/*!
139 * \brief a macro wrapper to update the evtOnDrawring event handler
140 * \param[in] __CB_ADDR the address of the arm_2d_helper_pfb_t object
141 * \param[in] __HANDLER the new handler
142 * \param[in] ... [Optional] an address (of user defined structure) passed to the
143 * event handler.
144 * \return arm_2d_err_t the process result
145 */
146#define ARM_2D_HELPER_PFB_UPDATE_ON_DRAW_HANDLER( \
147 __CB_ADDR, /* PFB Helper object address */ \
148 __HANDLER, /* new on-draw-handler function*/\
149 ...) /* An optional target address */ \
150 arm_2d_helper_pfb_update_dependency((__CB_ADDR), \
151 ARM_2D_PFB_DEPEND_ON_DRAWING, \
152 (arm_2d_helper_pfb_dependency_t []) {{ \
153 .evtOnDrawing = { \
154 .fnHandler = (__HANDLER), \
155 .pTarget = (NULL,##__VA_ARGS__),\
156 }, \
157 }})
158
159
160#define __IMPL_ARM_2D_REGION_LIST(__NAME, ...) \
161 enum { \
162 __NAME##_offset = __COUNTER__, \
163 }; \
164 __VA_ARGS__ \
165 arm_2d_region_list_item_t __NAME[] = {
166
167
168#define IMPL_ARM_2D_REGION_LIST(__NAME, ...) \
169 __IMPL_ARM_2D_REGION_LIST(__NAME,##__VA_ARGS__)
170
171
172#define END_IMPL_ARM_2D_REGION_LIST(...) \
173 };
174
175#define __ADD_REGION_TO_LIST(__NAME, ...) \
176 { \
177 .ptNext = (arm_2d_region_list_item_t *) \
178 &(__NAME[__COUNTER__ - __NAME##_offset]), \
179 .tRegion = { \
180 __VA_ARGS__ \
181 }, \
182 }
183
184#define ADD_REGION_TO_LIST(__NAME, ...) \
185 __ADD_REGION_TO_LIST(__NAME, ##__VA_ARGS__)
186
187
188#define __ADD_LAST_REGION_TO_LIST(__NAME, ...) \
189 { \
190 .ptNext = NULL, \
191 .tRegion = { \
192 __VA_ARGS__ \
193 }, \
194 }
195
196#define ADD_LAST_REGION_TO_LIST(__NAME, ...) \
197 __ADD_LAST_REGION_TO_LIST(__NAME, ##__VA_ARGS__)
198
199#define IMPL_PFB_ON_DRAW(__NAME) \
200 arm_fsm_rt_t __NAME(void *pTarget, \
201 const arm_2d_tile_t *ptTile, \
202 bool bIsNewFrame)
203
204#define IMPL_PFB_ON_LOW_LV_RENDERING(__NAME) \
205 void __NAME(void *pTarget, \
206 const arm_2d_pfb_t *ptPFB, \
207 bool bIsNewFrame)
208
209
210#define IMPL_PFB_ON_FRAME_SYNC_UP(__NAME) \
211 bool __NAME(void *pTarget)
212
213
214/*!
215 * \brief a macro wrapper in lowercase to help initialising PFB service
216 * \param[in] __CB_ADDR the address of the arm_2d_helper_pfb_t object
217 * \param[in] __SCREEN_WIDTH the width of the screen
218 * \param[in] __SCREEN_HEIGHT the hight of the screen
219 * \param[in] __PIXEL_TYPE the integer type of the pixel, i.e. uint8_t, uint16_t,
220 * uint32_t
221 * \param[in] __WIDTH the width of the PFB block
222 * \param[in] __HEIGHT the height of the PFB block
223 * \note For the same number of pixels in a PFB block, please priority the width
224 * over height, for example, 240 * 1 is better than 30 * 8
225 * \param[in] __PFB_NUM the number of PFB blocks in the built-in PFB pool.
226 * \param[in] ... a code block to add additional initializer, see example below:
227 * \return arm_2d_err_t the result of the initialisation process
228 *
229 * \code {.c}
230
231 static ARM_NOINIT arm_2d_helper_pfb_t s_tExamplePFB;
232 ...
233 // initialise FPB helper
234 if (init_arm_2d_helper_pfb(
235 &s_tExamplePFB, // FPB Helper object
236 __GLCD_CFG_SCEEN_WIDTH__, // screen width
237 __GLCD_CFG_SCEEN_HEIGHT__, // screen height
238 uint16_t, // colour date type
239 240, // PFB block width
240 1, // PFB block height
241 1, // number of PFB in the PFB pool
242 {
243 .evtOnLowLevelRendering = {
244 // callback for low level rendering
245 .fnHandler = &__pfb_render_handler,
246 },
247 .evtOnDrawing = {
248 // callback for drawing GUI
249 .fnHandler = &__pfb_draw_background_handler,
250 },
251 },
252 //.FrameBuffer.bSwapRGB16 = true,
253 ) < 0) {
254 //! error detected
255 assert(false);
256 }
257 * \endcode
258 *
259 */
260#define init_arm_2d_helper_pfb( __CB_ADDR, \
261 __SCREEN_WIDTH, \
262 __SCREEN_HEIGHT, \
263 __PIXEL_TYPE, \
264 __WIDTH, \
265 __HEIGHT, \
266 __PFB_NUM, \
267 ... \
268 ) \
269 ARM_2D_HELPER_PFB_INIT( \
270 __CB_ADDR, \
271 __SCREEN_WIDTH, \
272 __SCREEN_HEIGHT, \
273 __PIXEL_TYPE, \
274 __WIDTH, \
275 __HEIGHT, \
276 __PFB_NUM, \
277 ##__VA_ARGS__ \
278 )
279
280/*!
281 * \brief a macro wrapper to update the evtOnDrawring event handler
282 * \param[in] __CB_ADDR the address of the arm_2d_helper_pfb_t object
283 * \param[in] __HANDLER the new handler
284 * \param[in] ... [Optional] an address (of user defined structure) passed to the
285 * event handler.
286 * \return arm_2d_err_t the process result
287 */
288#define update_arm_2d_helper_pfb_on_draw_handler( \
289 __CB_ADDR, /* PFB Helper object address */ \
290 __HANDLER, /* new on-draw-handler function*/\
291 ...) /* An optional target address */ \
292 ARM_2D_HELPER_PFB_UPDATE_ON_DRAW_HANDLER( \
293 (__CB_ADDR), \
294 (__HANDLER),##__VA_ARGRS__)
295
296#define impl_arm_2d_region_list(__NAME, ...) \
297 IMPL_ARM_2D_REGION_LIST(__NAME,##__VA_ARGS__)
298#define add_region_to_list(__NAME, ...) \
299 ADD_REGION_TO_LIST(__NAME, ##__VA_ARGS__)
300#define add_last_region_to_list(__NAME, ...) \
301 ADD_LAST_REGION_TO_LIST(__NAME, ##__VA_ARGS__)
302#define end_impl_arm_2d_region_list(...) \
303 END_IMPL_ARM_2D_REGION_LIST(__VA_ARGS__)
304
305#define impl_pfb_on_draw(__NAME) IMPL_PFB_ON_DRAW(__NAME)
306#define impl_pfb_on_low_lv_rendering(__NAME) \
307 IMPL_PFB_ON_LOW_LV_RENDERING(__NAME)
308
309/*============================ TYPES =========================================*/
310
311/*!
312 * \brief the header of a PFB block
313 */
314typedef struct arm_2d_pfb_t {
315 struct arm_2d_pfb_t *ptNext; //!< next pfb block
316 arm_2d_tile_t tTile; //!< descriptor
317 bool bIsNewFrame; //!< a flag to indicate the starting of a frame
319
320/*!
321 * \brief the node of a region list
322 *
323 */
325 struct arm_2d_region_list_item_t *ptNext; //!< the next node
326 arm_2d_region_t tRegion; //!< the region
328
329/*!
330 * \brief the On-Drawing event handler for application layer
331 *
332 * \param[in] pTarget a user attached target address
333 * \param[in] ptTile a tile for the virtual screen
334 * \param[in] bIsNewFrame a flag indicate the starting of a new frame
335 * \return arm_fsm_rt_t the status of the FSM.
336 */
337typedef arm_fsm_rt_t arm_2d_helper_draw_handler_t(
338 void *pTarget,
339 const arm_2d_tile_t *ptTile,
340 bool bIsNewFrame);
341
342/*!
343 * \brief the On Low Level Rendering event handler for the low level (LCD Driver)
344 *
345 * \param[in] pTarget a user attached target address
346 * \param[in] ptPFB the PFB block
347 * \param[in] bIsNewFrame a flag indicate the starting of a new frame
348 */
350 void *pTarget,
351 const arm_2d_pfb_t *ptPFB,
352 bool bIsNewFrame);
353
354/*!
355 * \brief on low level render event
356 */
358 arm_2d_helper_render_handler_t *fnHandler; //!< event handler function
359 void *pTarget; //!< user attached target
361
362/*!
363 * \brief on drawing event
364 */
366 arm_2d_helper_draw_handler_t *fnHandler; //!< event handler function
367 void *pTarget; //!< user attached target
369
370/*!
371 * \brief the enumeration for events
372 *
373 */
374enum {
375 ARM_2D_PFB_DEPEND_ON_LOW_LEVEL_RENDERING = _BV(0), //!< On Low Level Rendering Event
376 ARM_2D_PFB_DEPEND_ON_DRAWING = _BV(1), //!< On Drawing Event
377 ARM_2D_PFB_DEPEND_ON_LOW_LEVEL_SYNC_UP = _BV(2), //!< On Low Level Sync-up Event
378 ARM_2D_PFB_DEPEND_ON_FRAME_SYNC_UP = _BV(3), //!< On Frame Sync-up Event
379};
380
381/*!
382 * \brief The PFB Helper Service Dependency
383 *
384 */
386 //! event handler for low level rendering
388
389 //! event handler for drawing GUI
391
392 //! low level rendering handler wants to sync-up (return arm_fsm_rt_wait_for_obj)
394
396
397/*!
398 * \brief PFB Helper configuration
399 *
400 */
402
403 arm_2d_region_t tDisplayArea; //!< screen description
404
405 struct {
406 arm_2d_pfb_t *ptPFBs; //!< current PFB block
407 arm_2d_size_t tFrameSize; //!< the size of the frame
408 uint32_t wBufferSize; //!< the buffer size
409 uint16_t hwPFBNum; //!< the number of PFB
410 uint16_t bDoNOTUpdateDefaultFrameBuffer : 1; //!< A flag to disable automatically default-framebuffer-registration
411 uint16_t bDisableDynamicFPBSize : 1; //!< A flag to disable resize of the PFB block
412 uint16_t bSwapRGB16 : 1; //!< A flag to enable swapping high and low bytes of an RGB16 pixel
413 uint16_t : 13;
414 } FrameBuffer; //!< frame buffer context
415
416 arm_2d_helper_pfb_dependency_t Dependency; //!< user registered dependency
417
419
420/*!
421 * \brief the PFB helper control block
422 *
423 */
424typedef struct arm_2d_helper_pfb_t {
425
426ARM_PRIVATE(
427 arm_2d_helper_pfb_cfg_t tCFG; //!< user configuration
428
429 struct {
430 arm_2d_region_t tDrawRegion;
431 arm_2d_region_t tTargetRegion;
432 arm_2d_region_list_item_t *ptDirtyRegion;
433 arm_2d_tile_t tPFBTile;
434 arm_2d_size_t tFrameSize;
435 bool bFirstIteration;
436 bool bIsRegionChanged;
437 uint8_t chPT;
438 struct {
439 uint8_t bIsNewFrame : 1;
440 uint8_t bIsFlushRequested :1;
441 };
442
443 arm_2d_pfb_t *ptCurrent;
444 arm_2d_pfb_t *ptFreeList;
445 struct {
446 arm_2d_pfb_t *ptHead;
447 arm_2d_pfb_t *ptTail;
448 }FlushFIFO;
449 arm_2d_tile_t *ptFrameBuffer;
450 } Adapter;
452
453 struct {
454 int32_t nTotalCycle; //!< cycles used by drawing
455 int32_t nRenderingCycle; //!< cycles used in LCD flushing
456 } Statistics; //!< performance statistics
457
459
460/*============================ GLOBAL VARIABLES ==============================*/
461/*============================ LOCAL VARIABLES ===============================*/
462/*============================ PROTOTYPES ====================================*/
463
464/*!
465 * \brief initialize pfb helper service
466 * \param[in] ptThis the pfb helper control block
467 * \param[in] ptCFG the configuration
468 * \return arm_2d_err_t the process result
469 */
470extern
471ARM_NONNULL(1,2)
474
475/*!
476 * \brief the task function for pfb helper
477 * \param[in] ptThis an initialised PFB control block
478 * \param[in] ptDirtyRegions a region list pending for refresh, NULL means
479 * refreshing the whole screen
480 * \retval arm_fsm_rt_cpl complete refreshing one frame
481 * \retval arm_fsm_rt_on_going the refreshing work is on-going
482 * \retval arm_fsm_rt_wait_for_obj user's OnDrawing event handler wants to wait
483 * for some objects, e.g. semaphore etc.
484 * \retval <0 An error is detected
485 */
486extern
487ARM_NONNULL(1)
489 arm_2d_region_list_item_t *ptDirtyRegions);
490
491/*!
492 * \brief update PFB dependency (event handlers)
493 * \param[in] ptThis the PFB control block
494 * \param[in] chMask the bit mask for event handlers
495 * \param[in] ptDependency the new dependency description
496 * \return arm_2d_err_t the process result
497 */
498extern
499ARM_NONNULL(1,3)
501 arm_2d_helper_pfb_t *ptThis,
502 uint_fast8_t chMask,
503 const arm_2d_helper_pfb_dependency_t *ptDependency);
504
505/*!
506 * \brief tell PFB helper that a low level LCD flushing work is complete
507 * \note This function is THREAD-SAFE, You can call this function asynchronously,
508 * e.g.
509 * - A ISR to indicate DMA-transfer complete event or
510 * - A different Thread
511 * \param[in] ptThis the PFB control block
512 * \param[in] ptPFB the used PFB block
513 */
514extern
515ARM_NONNULL(1,2)
517 arm_2d_pfb_t *ptPFB);
518
519/*! @} */
520
521#if defined(__clang__)
522# pragma clang diagnostic pop
523#endif
524
525#ifdef __cplusplus
526}
527#endif
528
529
530
531#endif