Arm-2D  
2D Image Processing Library for Cortex-M Processors
 
Loading...
Searching...
No Matches
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: 10. Dec 2022
25 * $Revision: V.1.3.7
26 *
27 * Target Processor: Cortex-M cores
28 * -------------------------------------------------------------------- */
29
30#ifndef __ARM_2D_HELPER_PFB_H__
31#define __ARM_2D_HELPER_PFB_H__
32
33/*============================ INCLUDES ======================================*/
34#include "arm_2d.h"
35
36#include "./__arm_2d_helper_common.h"
37
38#ifdef __cplusplus
39extern "C" {
40#endif
41
42
43#if defined(__clang__)
44# pragma clang diagnostic push
45# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
46# pragma clang diagnostic ignored "-Wpadded"
47#endif
48
49
50/*!
51 * \addtogroup gHelper 7 Helper Services
52 * @{
53 */
54
55/*============================ MACROS ========================================*/
56/*============================ MACROFIED FUNCTIONS ===========================*/
57
58/*!
59 * \brief a macro wrapper in uppercase to help initialising PFB service
60 * \param[in] __CB_ADDR the address of the arm_2d_helper_pfb_t object
61 * \param[in] __SCREEN_WIDTH the width of the screen
62 * \param[in] __SCREEN_HEIGHT the hight of the screen
63 * \param[in] __PIXEL_TYPE the integer type of the pixel, i.e. uint8_t, uint16_t,
64 * uint32_t
65 * \param[in] __WIDTH the width of the PFB block
66 * \param[in] __HEIGHT the height of the PFB block
67 * \note For the same number of pixels in a PFB block, please priority the width
68 * over height, for example, 240 * 1 is better than 30 * 8
69 * \param[in] __PFB_NUM the number of PFB blocks in the built-in PFB pool.
70 * \param[in] ... a code block to add additional initializer, see example below:
71 * \return arm_2d_err_t the result of the initialisation process
72 *
73 * \code {.c}
74
75 static ARM_NOINIT arm_2d_helper_pfb_t s_tExamplePFB;
76 ...
77 // initialise FPB helper
78 if (ARM_2D_HELPER_PFB_INIT(
79 &s_tExamplePFB, // FPB Helper object
80 __GLCD_CFG_SCEEN_WIDTH__, // screen width
81 __GLCD_CFG_SCEEN_HEIGHT__, // screen height
82 uint16_t, // colour date type
83 240, // PFB block width
84 1, // PFB block height
85 1, // number of PFB in the PFB pool
86 {
87 .evtOnLowLevelRendering = {
88 // callback for low level rendering
89 .fnHandler = &__pfb_render_handler,
90 },
91 .evtOnDrawing = {
92 // callback for drawing GUI
93 .fnHandler = &__pfb_draw_background_handler,
94 },
95 },
96 //.FrameBuffer.bSwapRGB16 = true,
97 ) < 0) {
98 //! error detected
99 assert(false);
100 }
101 * \endcode
102 *
103 */
104#define ARM_2D_HELPER_PFB_INIT( __CB_ADDR, /* PFB Helper object address */ \
105 __SCREEN_WIDTH, /* Screen width */ \
106 __SCREEN_HEIGHT,/* Screen height */ \
107 __PIXEL_TYPE, /* The type of the pixels */ \
108 __WIDTH, /* The width of the PFB block */\
109 __HEIGHT, /* The height of the PFB block*/\
110 __PFB_NUM, /* Block count in the PFB pool*/\
111 ... /* Event Handler */ \
112 ) \
113 ({ \
114 __attribute__((section(".bss.noinit.arm_2d_pfb_pool"))) \
115 static struct { \
116 arm_2d_pfb_t tFPB; \
117 __ALIGNED(4) \
118 __PIXEL_TYPE tBuffer[(__WIDTH) * (__HEIGHT)]; \
119 } s_tPFBs[__PFB_NUM]; \
120 \
121 arm_2d_helper_pfb_cfg_t tCFG = { \
122 .tDisplayArea.tSize = { \
123 .iWidth = (__SCREEN_WIDTH), \
124 .iHeight = (__SCREEN_HEIGHT), \
125 }, \
126 \
127 .FrameBuffer.ptPFBs = (arm_2d_pfb_t *)s_tPFBs, \
128 .FrameBuffer.tFrameSize = { \
129 .iWidth = (__WIDTH), \
130 .iHeight = (__HEIGHT), \
131 }, \
132 .FrameBuffer.wBufferSize = sizeof(s_tPFBs[0].tBuffer), \
133 .FrameBuffer.hwPFBNum = dimof(s_tPFBs), \
134 .Dependency = \
135 __VA_ARGS__ \
136 }; \
137 \
138 arm_2d_helper_pfb_init((__CB_ADDR), &tCFG); \
139 })
140
141/*!
142 * \brief a macro wrapper to update the evtOnDrawring event handler
143 * \param[in] __CB_ADDR the address of the arm_2d_helper_pfb_t object
144 * \param[in] __HANDLER the new handler
145 * \param[in] ... [Optional] an address (of user defined structure) passed to the
146 * event handler.
147 * \return arm_2d_err_t the process result
148 */
149#define ARM_2D_HELPER_PFB_UPDATE_ON_DRAW_HANDLER( \
150 __CB_ADDR, /* PFB Helper object address */ \
151 __HANDLER, /* new on-draw-handler function*/\
152 ...) /* An optional target address */ \
153 arm_2d_helper_pfb_update_dependency((__CB_ADDR), \
154 ARM_2D_PFB_DEPEND_ON_DRAWING, \
155 (arm_2d_helper_pfb_dependency_t []) {{ \
156 .evtOnDrawing = { \
157 .fnHandler = (__HANDLER), \
158 .pTarget = (NULL,##__VA_ARGS__),\
159 }, \
160 }})
161
162
163#define __IMPL_ARM_2D_REGION_LIST(__NAME, ...) \
164 enum { \
165 __NAME##_offset = __COUNTER__, \
166 }; \
167 __VA_ARGS__ \
168 arm_2d_region_list_item_t __NAME[] = {
169
170
171#define IMPL_ARM_2D_REGION_LIST(__NAME, ...) \
172 __IMPL_ARM_2D_REGION_LIST(__NAME,##__VA_ARGS__)
173
174
175#define END_IMPL_ARM_2D_REGION_LIST(...) \
176 };
177
178#define __ADD_REGION_TO_LIST(__NAME, ...) \
179 { \
180 .ptNext = (arm_2d_region_list_item_t *) \
181 &(__NAME[__COUNTER__ - __NAME##_offset]), \
182 .tRegion = { \
183 __VA_ARGS__ \
184 }, \
185 }
186
187#define ADD_REGION_TO_LIST(__NAME, ...) \
188 __ADD_REGION_TO_LIST(__NAME, ##__VA_ARGS__)
189
190
191#define __ADD_LAST_REGION_TO_LIST(__NAME, ...) \
192 { \
193 .ptNext = NULL, \
194 .tRegion = { \
195 __VA_ARGS__ \
196 }, \
197 }
198
199#define ADD_LAST_REGION_TO_LIST(__NAME, ...) \
200 __ADD_LAST_REGION_TO_LIST(__NAME, ##__VA_ARGS__)
201
202
203#define IMPL_PFB_ON_DRAW(__NAME) IMPL_ON_DRAW_EVT(__NAME)
204
205
206#define IMPL_PFB_ON_LOW_LV_RENDERING(__NAME) \
207 void __NAME(void *pTarget, \
208 const arm_2d_pfb_t *ptPFB, \
209 bool bIsNewFrame)
210
211
212#define IMPL_PFB_ON_FRAME_SYNC_UP(__NAME) \
213 bool __NAME(void *pTarget)
214
215
216/*!
217 * \brief a macro wrapper in lowercase to help initialising PFB service
218 * \param[in] __CB_ADDR the address of the arm_2d_helper_pfb_t object
219 * \param[in] __SCREEN_WIDTH the width of the screen
220 * \param[in] __SCREEN_HEIGHT the hight of the screen
221 * \param[in] __PIXEL_TYPE the integer type of the pixel, i.e. uint8_t, uint16_t,
222 * uint32_t
223 * \param[in] __WIDTH the width of the PFB block
224 * \param[in] __HEIGHT the height of the PFB block
225 * \note For the same number of pixels in a PFB block, please priority the width
226 * over height, for example, 240 * 1 is better than 30 * 8
227 * \param[in] __PFB_NUM the number of PFB blocks in the built-in PFB pool.
228 * \param[in] ... a code block to add additional initializer, see example below:
229 * \return arm_2d_err_t the result of the initialisation process
230 *
231 * \code {.c}
232
233 static ARM_NOINIT arm_2d_helper_pfb_t s_tExamplePFB;
234 ...
235 // initialise FPB helper
236 if (init_arm_2d_helper_pfb(
237 &s_tExamplePFB, // FPB Helper object
238 __GLCD_CFG_SCEEN_WIDTH__, // screen width
239 __GLCD_CFG_SCEEN_HEIGHT__, // screen height
240 uint16_t, // colour date type
241 240, // PFB block width
242 1, // PFB block height
243 1, // number of PFB in the PFB pool
244 {
245 .evtOnLowLevelRendering = {
246 // callback for low level rendering
247 .fnHandler = &__pfb_render_handler,
248 },
249 .evtOnDrawing = {
250 // callback for drawing GUI
251 .fnHandler = &__pfb_draw_background_handler,
252 },
253 },
254 //.FrameBuffer.bSwapRGB16 = true,
255 ) < 0) {
256 //! error detected
257 assert(false);
258 }
259 * \endcode
260 *
261 */
262#define init_arm_2d_helper_pfb( __CB_ADDR, \
263 __SCREEN_WIDTH, \
264 __SCREEN_HEIGHT, \
265 __PIXEL_TYPE, \
266 __WIDTH, \
267 __HEIGHT, \
268 __PFB_NUM, \
269 ... \
270 ) \
271 ARM_2D_HELPER_PFB_INIT( \
272 __CB_ADDR, \
273 __SCREEN_WIDTH, \
274 __SCREEN_HEIGHT, \
275 __PIXEL_TYPE, \
276 __WIDTH, \
277 __HEIGHT, \
278 __PFB_NUM, \
279 ##__VA_ARGS__ \
280 )
281
282/*!
283 * \brief a macro wrapper to update the evtOnDrawring event handler
284 * \param[in] __CB_ADDR the address of the arm_2d_helper_pfb_t object
285 * \param[in] __HANDLER the new handler
286 * \param[in] ... [Optional] an address (of user defined structure) passed to the
287 * event handler.
288 * \return arm_2d_err_t the process result
289 */
290#define update_arm_2d_helper_pfb_on_draw_handler( \
291 __CB_ADDR, /* PFB Helper object address */ \
292 __HANDLER, /* new on-draw-handler function*/\
293 ...) /* An optional target address */ \
294 ARM_2D_HELPER_PFB_UPDATE_ON_DRAW_HANDLER( \
295 (__CB_ADDR), \
296 (__HANDLER),##__VA_ARGRS__)
297
298/*!
299 * \brief tell PFB helper that a low level LCD flushing work is complete
300 * \note This function is THREAD-SAFE, You can call this function asynchronously,
301 * e.g.
302 * - A ISR to indicate DMA-transfer complete event or
303 * - A different Thread
304 * \param[in] ptThis the PFB control block
305 * \param[in] ... the used PFB block.
306 * \note please do not use this parameter, it is only kept for backward
307 * compatability.
308 */
309#define arm_2d_helper_pfb_report_rendering_complete(__PFB_HELPER_PTR,...) \
310 __arm_2d_helper_pfb_report_rendering_complete((__PFB_HELPER_PTR), \
311 (NULL,##__VA_ARGS__))
312
313
314#define impl_arm_2d_region_list(__NAME, ...) \
315 IMPL_ARM_2D_REGION_LIST(__NAME,##__VA_ARGS__)
316#define add_region_to_list(__NAME, ...) \
317 ADD_REGION_TO_LIST(__NAME, ##__VA_ARGS__)
318#define add_last_region_to_list(__NAME, ...) \
319 ADD_LAST_REGION_TO_LIST(__NAME, ##__VA_ARGS__)
320#define end_impl_arm_2d_region_list(...) \
321 END_IMPL_ARM_2D_REGION_LIST(__VA_ARGS__)
322
323#define impl_pfb_on_draw(__NAME) IMPL_PFB_ON_DRAW(__NAME)
324#define impl_pfb_on_low_lv_rendering(__NAME) \
325 IMPL_PFB_ON_LOW_LV_RENDERING(__NAME)
326
327/*============================ TYPES =========================================*/
328
330/*!
331 * \brief the header of a PFB block
332 */
333typedef struct arm_2d_pfb_t {
334 struct arm_2d_pfb_t *ptNext; //!< next pfb block
335 arm_2d_helper_pfb_t *ptPFBHelper; //!< the pfb helper service current PFB block comes from
336 arm_2d_tile_t tTile; //!< descriptor
337 uint32_t u24Size : 24;
338 uint32_t : 7;
339 uint32_t bIsNewFrame : 1; //!< a flag to indicate the starting of a frame
341
342/*!
343 * \brief the node of a region list
344 *
345 */
347 struct arm_2d_region_list_item_t *ptNext; //!< the next node
348 arm_2d_region_t tRegion; //!< the region
350
351/*!
352 * \brief the On Low Level Rendering event handler for the low level (LCD Driver)
353 *
354 * \param[in] pTarget a user attached target address
355 * \param[in] ptPFB the PFB block
356 * \param[in] bIsNewFrame a flag indicate the starting of a new frame
357 */
359 void *pTarget,
360 const arm_2d_pfb_t *ptPFB,
361 bool bIsNewFrame);
362
363/*!
364 * \brief on low level render event
365 */
367 arm_2d_helper_render_handler_t *fnHandler; //!< event handler function
368 void *pTarget; //!< user attached target
370
371
372
373/*!
374 * \brief the enumeration for events
375 *
376 */
377enum {
378 ARM_2D_PFB_DEPEND_ON_LOW_LEVEL_RENDERING = _BV(0), //!< On Low Level Rendering Event
379 ARM_2D_PFB_DEPEND_ON_DRAWING = _BV(1), //!< On Drawing Event
380 ARM_2D_PFB_DEPEND_ON_LOW_LEVEL_SYNC_UP = _BV(2), //!< On Low Level Sync-up Event
381 ARM_2D_PFB_DEPEND_ON_FRAME_SYNC_UP = _BV(3), //!< On Frame Sync-up Event
382 ARM_2D_PFB_DEPEND_ON_EACH_FRAME_CPL = _BV(4), //!< On Each Frame Complete Event
383 ARM_2D_PFB_DEPEND_ON_NAVIGATION = _BV(5), //!< On Drawing Navigation Event
384};
385
386/*!
387 * \brief The PFB Helper Service Dependency
388 *
389 */
391 //! event handler for low level rendering
393
394 //! event handler for drawing GUI
395 arm_2d_helper_draw_evt_t evtOnDrawing;
396
397 //! low level rendering handler wants to sync-up (return arm_fsm_rt_wait_for_obj)
399
400 //! event handler for each frame complete
402
403 //! event handler for drawing GUI
404 struct {
405 arm_2d_helper_draw_evt_t evtOnDrawing;
406 arm_2d_region_list_item_t *ptDirtyRegion;
408
410
411/*!
412 * \brief PFB Helper configuration
413 *
414 */
416
417 arm_2d_region_t tDisplayArea; //!< screen description
418
419 struct {
420 arm_2d_pfb_t *ptPFBs; //!< current PFB block
421 arm_2d_size_t tFrameSize; //!< the size of the frame
422 uint32_t wBufferSize; //!< the buffer size
423 uint16_t hwPFBNum; //!< the number of PFB
424 uint16_t bDoNOTUpdateDefaultFrameBuffer : 1; //!< A flag to disable automatically default-framebuffer-registration
425 uint16_t bDisableDynamicFPBSize : 1; //!< A flag to disable resize of the PFB block
426 uint16_t bSwapRGB16 : 1; //!< A flag to enable swapping high and low bytes of an RGB16 pixel
427 uint16_t : 9;
428 uint16_t u4PoolReserve : 4; //!< reserve specific number of PFB for other helper services
429
430 } FrameBuffer; //!< frame buffer context
431
432 arm_2d_helper_pfb_dependency_t Dependency; //!< user registered dependency
433
435
436/*!
437 * \brief the PFB helper control block
438 *
439 */
441
442ARM_PRIVATE(
443 arm_2d_helper_pfb_cfg_t tCFG; //!< user configuration
444
445 struct {
446 arm_2d_region_t tDrawRegion;
447 arm_2d_region_t tTargetRegion;
448 arm_2d_region_list_item_t *ptDirtyRegion;
449 arm_2d_tile_t tPFBTile;
450 arm_2d_size_t tFrameSize;
451 bool bFirstIteration;
452 bool bIsRegionChanged;
453 uint8_t chPT;
454 struct {
455 uint8_t bIsNewFrame : 1;
456 uint8_t bIsFlushRequested :1;
457 uint8_t bNoAdditionalDirtyRegionList;
458 };
459 uint16_t hwFreePFBCount;
460 arm_2d_pfb_t *ptCurrent;
461 arm_2d_pfb_t *ptFreeList;
462 arm_2d_pfb_t *ptFlushing;
463 struct {
464 arm_2d_pfb_t *ptHead;
465 arm_2d_pfb_t *ptTail;
466 }FlushFIFO;
467 arm_2d_tile_t *ptFrameBuffer;
468 } Adapter;
470
471 struct {
472 int64_t lTimestamp; //!< PLEASE DO NOT USE
473 int32_t nTotalCycle; //!< cycles used by drawing
474 int32_t nRenderingCycle; //!< cycles used in LCD flushing
475 } Statistics; //!< performance statistics
476
477};
478
479/*============================ GLOBAL VARIABLES ==============================*/
480/*============================ LOCAL VARIABLES ===============================*/
481/*============================ PROTOTYPES ====================================*/
482
483/*!
484 * \brief initialize pfb helper service
485 * \param[in] ptThis the pfb helper control block
486 * \param[in] ptCFG the configuration
487 * \return arm_2d_err_t the process result
488 */
489extern
490ARM_NONNULL(1,2)
493
494/*!
495 * \brief get the display (screen) region
496 * \param[in] ptThis the pfb helper control block
497 * \return arm_2d_region_t the screen region
498 */
499extern
500ARM_NONNULL(1)
502
503/*!
504 * \brief the task function for pfb helper
505 * \param[in] ptThis an initialised PFB control block
506 * \param[in] ptDirtyRegions a region list pending for refresh, NULL means
507 * refreshing the whole screen
508 * \retval arm_fsm_rt_cpl complete refreshing one frame
509 * \retval arm_fsm_rt_on_going the refreshing work is on-going
510 * \retval arm_fsm_rt_wait_for_obj user's OnDrawing event handler wants to wait
511 * for some objects, e.g. semaphore etc.
512 * \retval <0 An error is detected
513 */
514extern
515ARM_NONNULL(1)
517 arm_2d_region_list_item_t *ptDirtyRegions);
518
519/*!
520 * \brief flush the FPB FIFO
521 * \note This function is THREAD-SAFE
522 * \note For normal usage, please DO NOT use this function unless you know what
523 * you are doing.
524 * \param[in] ptThis an initialised PFB control block
525 */
526extern
527ARM_NONNULL(1)
529
530/*!
531 * \brief update PFB dependency (event handlers)
532 * \param[in] ptThis the PFB control block
533 * \param[in] chMask the bit mask for event handlers
534 * \param[in] ptDependency the new dependency description
535 * \return arm_2d_err_t the process result
536 */
537extern
538ARM_NONNULL(1,3)
540 arm_2d_helper_pfb_t *ptThis,
541 uint_fast8_t chMask,
542 const arm_2d_helper_pfb_dependency_t *ptDependency);
543
544/*!
545 * \brief tell PFB helper that a low level LCD flushing work is complete
546 * \note This function is THREAD-SAFE, You can call this function asynchronously,
547 * e.g.
548 * - A ISR to indicate DMA-transfer complete event or
549 * - A different Thread
550 * \param[in] ptThis the PFB control block
551 * \param[in] ptPFB the used PFB block
552 */
553extern
554ARM_NONNULL(1)
556 arm_2d_pfb_t *ptPFB);
557
558/*!
559 * \brief swap the high and low bytes for each rgb16 pixel
560 *
561 * \param[in] phwBuffer the pixel buffer
562 * \note the phwBuffer MUST aligned to half-word addresses
563 *
564 * \param[in] wSize the number of pixels
565 */
566extern
567void arm_2d_helper_swap_rgb16(uint16_t *phwBuffer, uint32_t wCount);
568
569/*!
570 * \brief try to get a PFB block from the pool
571 * \param[in] ptThis the PFB control block
572 * \retval NULL the pool is empty
573 * \retval !NULL a valid pfb block
574 */
575extern
576ARM_NONNULL(1)
578
579/*!
580 * \brief free a PFB block to the pool
581 * \param[in] ptThis the PFB control block
582 * \param[in] ptPFB the target PFB block
583 */
584extern
585ARM_NONNULL(1)
587
588/*! @} */
589
590#if defined(__clang__)
591# pragma clang diagnostic pop
592#endif
593
594#ifdef __cplusplus
595}
596#endif
597
598
599
600#endif